diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /intern/cycles/render | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'intern/cycles/render')
59 files changed, 22447 insertions, 22120 deletions
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 140fcb206dc..378957d21f4 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -1,86 +1,86 @@ set(INC - .. - ../../glew-mx + .. + ../../glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_DIR} + ${GLEW_INCLUDE_DIR} ) set(SRC - attribute.cpp - background.cpp - bake.cpp - buffers.cpp - camera.cpp - constant_fold.cpp - coverage.cpp - denoising.cpp - film.cpp - graph.cpp - image.cpp - integrator.cpp - light.cpp - merge.cpp - mesh.cpp - mesh_displace.cpp - mesh_subdivision.cpp - mesh_volume.cpp - nodes.cpp - object.cpp - osl.cpp - particles.cpp - curves.cpp - scene.cpp - session.cpp - shader.cpp - sobol.cpp - stats.cpp - svm.cpp - tables.cpp - tile.cpp + attribute.cpp + background.cpp + bake.cpp + buffers.cpp + camera.cpp + constant_fold.cpp + coverage.cpp + denoising.cpp + film.cpp + graph.cpp + image.cpp + integrator.cpp + light.cpp + merge.cpp + mesh.cpp + mesh_displace.cpp + mesh_subdivision.cpp + mesh_volume.cpp + nodes.cpp + object.cpp + osl.cpp + particles.cpp + curves.cpp + scene.cpp + session.cpp + shader.cpp + sobol.cpp + stats.cpp + svm.cpp + tables.cpp + tile.cpp ) set(SRC_HEADERS - attribute.h - bake.h - background.h - buffers.h - camera.h - constant_fold.h - coverage.h - denoising.h - film.h - graph.h - image.h - integrator.h - light.h - merge.h - mesh.h - nodes.h - object.h - osl.h - particles.h - curves.h - scene.h - session.h - shader.h - sobol.h - stats.h - svm.h - tables.h - tile.h + attribute.h + bake.h + background.h + buffers.h + camera.h + constant_fold.h + coverage.h + denoising.h + film.h + graph.h + image.h + integrator.h + light.h + merge.h + mesh.h + nodes.h + object.h + osl.h + particles.h + curves.h + scene.h + session.h + shader.h + sobol.h + stats.h + svm.h + tables.h + tile.h ) set(LIB - cycles_bvh + cycles_bvh ) if(WITH_CYCLES_OSL) - list(APPEND LIB - cycles_kernel_osl - ) + list(APPEND LIB + cycles_kernel_osl + ) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}") diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index f7788b6a490..dad6cb4fe6d 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -27,319 +27,316 @@ CCL_NAMESPACE_BEGIN Attribute::~Attribute() { - /* for voxel data, we need to remove the image from the image manager */ - if(element == ATTR_ELEMENT_VOXEL) { - VoxelAttribute *voxel_data = data_voxel(); + /* for voxel data, we need to remove the image from the image manager */ + if (element == ATTR_ELEMENT_VOXEL) { + VoxelAttribute *voxel_data = data_voxel(); - if(voxel_data && voxel_data->slot != -1) { - voxel_data->manager->remove_image(voxel_data->slot); - } - } + if (voxel_data && voxel_data->slot != -1) { + voxel_data->manager->remove_image(voxel_data->slot); + } + } } void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) { - name = name_; - type = type_; - element = element_; - std = ATTR_STD_NONE; - flags = 0; + name = name_; + type = type_; + element = element_; + std = ATTR_STD_NONE; + flags = 0; - /* string and matrix not supported! */ - assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor || - type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || - type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || - type == TypeFloat2); + /* string and matrix not supported! */ + assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor || + type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || + type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2); } void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only) { - if(reserve_only) { - buffer.reserve(buffer_size(mesh, prim)); - } - else { - buffer.resize(buffer_size(mesh, prim), 0); - } + if (reserve_only) { + buffer.reserve(buffer_size(mesh, prim)); + } + else { + buffer.resize(buffer_size(mesh, prim), 0); + } } void Attribute::resize(size_t num_elements) { - buffer.resize(num_elements * data_sizeof(), 0); + buffer.resize(num_elements * data_sizeof(), 0); } -void Attribute::add(const float& f) +void Attribute::add(const float &f) { - assert(data_sizeof() == sizeof(float)); + assert(data_sizeof() == sizeof(float)); - char *data = (char*)&f; - size_t size = sizeof(f); + char *data = (char *)&f; + size_t size = sizeof(f); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } -void Attribute::add(const uchar4& f) +void Attribute::add(const uchar4 &f) { - assert(data_sizeof() == sizeof(uchar4)); + assert(data_sizeof() == sizeof(uchar4)); - char *data = (char*)&f; - size_t size = sizeof(f); + char *data = (char *)&f; + size_t size = sizeof(f); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } -void Attribute::add(const float2& f) +void Attribute::add(const float2 &f) { - assert(data_sizeof() == sizeof(float2)); + assert(data_sizeof() == sizeof(float2)); - char *data = (char*)&f; - size_t size = sizeof(f); + char *data = (char *)&f; + size_t size = sizeof(f); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } -void Attribute::add(const float3& f) +void Attribute::add(const float3 &f) { - assert(data_sizeof() == sizeof(float3)); + assert(data_sizeof() == sizeof(float3)); - char *data = (char*)&f; - size_t size = sizeof(f); + char *data = (char *)&f; + size_t size = sizeof(f); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } -void Attribute::add(const Transform& f) +void Attribute::add(const Transform &f) { - assert(data_sizeof() == sizeof(Transform)); + assert(data_sizeof() == sizeof(Transform)); - char *data = (char*)&f; - size_t size = sizeof(f); + char *data = (char *)&f; + size_t size = sizeof(f); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } -void Attribute::add(const VoxelAttribute& f) +void Attribute::add(const VoxelAttribute &f) { - assert(data_sizeof() == sizeof(VoxelAttribute)); + assert(data_sizeof() == sizeof(VoxelAttribute)); - char *data = (char*)&f; - size_t size = sizeof(f); + char *data = (char *)&f; + size_t size = sizeof(f); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } void Attribute::add(const char *data) { - size_t size = data_sizeof(); + size_t size = data_sizeof(); - for(size_t i = 0; i < size; i++) - buffer.push_back(data[i]); + for (size_t i = 0; i < size; i++) + buffer.push_back(data[i]); } size_t Attribute::data_sizeof() const { - if(element == ATTR_ELEMENT_VOXEL) - return sizeof(VoxelAttribute); - else if(element == ATTR_ELEMENT_CORNER_BYTE) - return sizeof(uchar4); - else if(type == TypeDesc::TypeFloat) - return sizeof(float); - else if(type == TypeFloat2) - return sizeof(float2); - else if(type == TypeDesc::TypeMatrix) - return sizeof(Transform); - else - return sizeof(float3); + if (element == ATTR_ELEMENT_VOXEL) + return sizeof(VoxelAttribute); + else if (element == ATTR_ELEMENT_CORNER_BYTE) + return sizeof(uchar4); + else if (type == TypeDesc::TypeFloat) + return sizeof(float); + else if (type == TypeFloat2) + return sizeof(float2); + else if (type == TypeDesc::TypeMatrix) + return sizeof(Transform); + else + return sizeof(float3); } size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const { - if(flags & ATTR_FINAL_SIZE) { - return buffer.size() / data_sizeof(); - } - - size_t size; - - switch(element) { - case ATTR_ELEMENT_OBJECT: - case ATTR_ELEMENT_MESH: - case ATTR_ELEMENT_VOXEL: - size = 1; - break; - case ATTR_ELEMENT_VERTEX: - size = mesh->verts.size() + mesh->num_ngons; - if(prim == ATTR_PRIM_SUBD) { - size -= mesh->num_subd_verts; - } - break; - case ATTR_ELEMENT_VERTEX_MOTION: - size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); - if(prim == ATTR_PRIM_SUBD) { - size -= mesh->num_subd_verts * (mesh->motion_steps - 1); - } - break; - case ATTR_ELEMENT_FACE: - if(prim == ATTR_PRIM_TRIANGLE) { - size = mesh->num_triangles(); - } - else { - size = mesh->subd_faces.size() + mesh->num_ngons; - } - break; - case ATTR_ELEMENT_CORNER: - case ATTR_ELEMENT_CORNER_BYTE: - if(prim == ATTR_PRIM_TRIANGLE) { - size = mesh->num_triangles()*3; - } - else { - size = mesh->subd_face_corners.size() + mesh->num_ngons; - } - break; - case ATTR_ELEMENT_CURVE: - size = mesh->num_curves(); - break; - case ATTR_ELEMENT_CURVE_KEY: - size = mesh->curve_keys.size(); - break; - case ATTR_ELEMENT_CURVE_KEY_MOTION: - size = mesh->curve_keys.size() * (mesh->motion_steps - 1); - break; - default: - size = 0; - break; - } - - return size; + if (flags & ATTR_FINAL_SIZE) { + return buffer.size() / data_sizeof(); + } + + size_t size; + + switch (element) { + case ATTR_ELEMENT_OBJECT: + case ATTR_ELEMENT_MESH: + case ATTR_ELEMENT_VOXEL: + size = 1; + break; + case ATTR_ELEMENT_VERTEX: + size = mesh->verts.size() + mesh->num_ngons; + if (prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts; + } + break; + case ATTR_ELEMENT_VERTEX_MOTION: + size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); + if (prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts * (mesh->motion_steps - 1); + } + break; + case ATTR_ELEMENT_FACE: + if (prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles(); + } + else { + size = mesh->subd_faces.size() + mesh->num_ngons; + } + break; + case ATTR_ELEMENT_CORNER: + case ATTR_ELEMENT_CORNER_BYTE: + if (prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles() * 3; + } + else { + size = mesh->subd_face_corners.size() + mesh->num_ngons; + } + break; + case ATTR_ELEMENT_CURVE: + size = mesh->num_curves(); + break; + case ATTR_ELEMENT_CURVE_KEY: + size = mesh->curve_keys.size(); + break; + case ATTR_ELEMENT_CURVE_KEY_MOTION: + size = mesh->curve_keys.size() * (mesh->motion_steps - 1); + break; + default: + size = 0; + break; + } + + return size; } size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const { - return element_size(mesh, prim)*data_sizeof(); + return element_size(mesh, prim) * data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) { - if(a == b) - return true; + if (a == b) + return true; - if(a == TypeDesc::TypeColor || a == TypeDesc::TypePoint || - a == TypeDesc::TypeVector || a == TypeDesc::TypeNormal) - { - if(b == TypeDesc::TypeColor || b == TypeDesc::TypePoint || - b == TypeDesc::TypeVector || b == TypeDesc::TypeNormal) - { - return true; - } - } - return false; + if (a == TypeDesc::TypeColor || a == TypeDesc::TypePoint || a == TypeDesc::TypeVector || + a == TypeDesc::TypeNormal) { + if (b == TypeDesc::TypeColor || b == TypeDesc::TypePoint || b == TypeDesc::TypeVector || + b == TypeDesc::TypeNormal) { + return true; + } + } + return false; } -void Attribute::zero_data(void* dst) +void Attribute::zero_data(void *dst) { - memset(dst, 0, data_sizeof()); + memset(dst, 0, data_sizeof()); } -void Attribute::add_with_weight(void* dst, void* src, float weight) +void Attribute::add_with_weight(void *dst, void *src, float weight) { - if(element == ATTR_ELEMENT_CORNER_BYTE) { - for(int i = 0; i < 4; i++) { - ((uchar*)dst)[i] += uchar(((uchar*)src)[i] * weight); - } - } - else if(same_storage(type, TypeDesc::TypeFloat)) { - *((float*)dst) += *((float*)src) * weight; - } - else if(same_storage(type, TypeDesc::TypeVector)) { - *((float4*)dst) += *((float4*)src) * weight; - } - else { - assert(!"not implemented for this type"); - } + if (element == ATTR_ELEMENT_CORNER_BYTE) { + for (int i = 0; i < 4; i++) { + ((uchar *)dst)[i] += uchar(((uchar *)src)[i] * weight); + } + } + else if (same_storage(type, TypeDesc::TypeFloat)) { + *((float *)dst) += *((float *)src) * weight; + } + else if (same_storage(type, TypeDesc::TypeVector)) { + *((float4 *)dst) += *((float4 *)src) * weight; + } + else { + assert(!"not implemented for this type"); + } } const char *Attribute::standard_name(AttributeStandard std) { - switch(std) { - case ATTR_STD_VERTEX_NORMAL: - return "N"; - case ATTR_STD_FACE_NORMAL: - return "Ng"; - case ATTR_STD_UV: - return "uv"; - case ATTR_STD_GENERATED: - return "generated"; - case ATTR_STD_GENERATED_TRANSFORM: - return "generated_transform"; - case ATTR_STD_UV_TANGENT: - return "tangent"; - case ATTR_STD_UV_TANGENT_SIGN: - return "tangent_sign"; - case ATTR_STD_POSITION_UNDEFORMED: - return "undeformed"; - case ATTR_STD_POSITION_UNDISPLACED: - return "undisplaced"; - case ATTR_STD_MOTION_VERTEX_POSITION: - return "motion_P"; - case ATTR_STD_MOTION_VERTEX_NORMAL: - return "motion_N"; - case ATTR_STD_PARTICLE: - return "particle"; - case ATTR_STD_CURVE_INTERCEPT: - return "curve_intercept"; - case ATTR_STD_CURVE_RANDOM: - return "curve_random"; - case ATTR_STD_PTEX_FACE_ID: - return "ptex_face_id"; - case ATTR_STD_PTEX_UV: - return "ptex_uv"; - case ATTR_STD_VOLUME_DENSITY: - return "density"; - case ATTR_STD_VOLUME_COLOR: - return "color"; - case ATTR_STD_VOLUME_FLAME: - return "flame"; - case ATTR_STD_VOLUME_HEAT: - return "heat"; - case ATTR_STD_VOLUME_TEMPERATURE: - return "temperature"; - case ATTR_STD_VOLUME_VELOCITY: - return "velocity"; - case ATTR_STD_POINTINESS: - return "pointiness"; - case ATTR_STD_NOT_FOUND: - case ATTR_STD_NONE: - case ATTR_STD_NUM: - return ""; - } - - return ""; + switch (std) { + case ATTR_STD_VERTEX_NORMAL: + return "N"; + case ATTR_STD_FACE_NORMAL: + return "Ng"; + case ATTR_STD_UV: + return "uv"; + case ATTR_STD_GENERATED: + return "generated"; + case ATTR_STD_GENERATED_TRANSFORM: + return "generated_transform"; + case ATTR_STD_UV_TANGENT: + return "tangent"; + case ATTR_STD_UV_TANGENT_SIGN: + return "tangent_sign"; + case ATTR_STD_POSITION_UNDEFORMED: + return "undeformed"; + case ATTR_STD_POSITION_UNDISPLACED: + return "undisplaced"; + case ATTR_STD_MOTION_VERTEX_POSITION: + return "motion_P"; + case ATTR_STD_MOTION_VERTEX_NORMAL: + return "motion_N"; + case ATTR_STD_PARTICLE: + return "particle"; + case ATTR_STD_CURVE_INTERCEPT: + return "curve_intercept"; + case ATTR_STD_CURVE_RANDOM: + return "curve_random"; + case ATTR_STD_PTEX_FACE_ID: + return "ptex_face_id"; + case ATTR_STD_PTEX_UV: + return "ptex_uv"; + case ATTR_STD_VOLUME_DENSITY: + return "density"; + case ATTR_STD_VOLUME_COLOR: + return "color"; + case ATTR_STD_VOLUME_FLAME: + return "flame"; + case ATTR_STD_VOLUME_HEAT: + return "heat"; + case ATTR_STD_VOLUME_TEMPERATURE: + return "temperature"; + case ATTR_STD_VOLUME_VELOCITY: + return "velocity"; + case ATTR_STD_POINTINESS: + return "pointiness"; + case ATTR_STD_NOT_FOUND: + case ATTR_STD_NONE: + case ATTR_STD_NUM: + return ""; + } + + return ""; } AttributeStandard Attribute::name_standard(const char *name) { - if(name) { - for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) { - if(strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) { - return (AttributeStandard)std; - } - } - } + if (name) { + for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) { + if (strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) { + return (AttributeStandard)std; + } + } + } - return ATTR_STD_NONE; + return ATTR_STD_NONE; } /* Attribute Set */ AttributeSet::AttributeSet() { - triangle_mesh = NULL; - curve_mesh = NULL; - subd_mesh = NULL; + triangle_mesh = NULL; + curve_mesh = NULL; + subd_mesh = NULL; } AttributeSet::~AttributeSet() @@ -348,280 +345,280 @@ AttributeSet::~AttributeSet() Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element) { - Attribute *attr = find(name); + Attribute *attr = find(name); - if(attr) { - /* return if same already exists */ - if(attr->type == type && attr->element == element) - return attr; + if (attr) { + /* return if same already exists */ + if (attr->type == type && attr->element == element) + return attr; - /* overwrite attribute with same name but different type/element */ - remove(name); - } + /* overwrite attribute with same name but different type/element */ + remove(name); + } #if __cplusplus >= 201103L - attributes.emplace_back(); - attr = &attributes.back(); - attr->set(name, type, element); + attributes.emplace_back(); + attr = &attributes.back(); + attr->set(name, type, element); #else - { - Attribute attr_temp; - attr_temp.set(name, type, element); - attributes.push_back(attr_temp); - attr = &attributes.back(); - } + { + Attribute attr_temp; + attr_temp.set(name, type, element); + attributes.push_back(attr_temp); + attr = &attributes.back(); + } #endif - /* this is weak .. */ - if(triangle_mesh) - attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); - if(curve_mesh) - attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); - if(subd_mesh) - attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); + /* this is weak .. */ + if (triangle_mesh) + attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); + if (curve_mesh) + attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); + if (subd_mesh) + attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); - return attr; + return attr; } Attribute *AttributeSet::find(ustring name) const { - foreach(const Attribute& attr, attributes) - if(attr.name == name) - return (Attribute*)&attr; + foreach (const Attribute &attr, attributes) + if (attr.name == name) + return (Attribute *)&attr; - return NULL; + return NULL; } void AttributeSet::remove(ustring name) { - Attribute *attr = find(name); + Attribute *attr = find(name); - if(attr) { - list<Attribute>::iterator it; + if (attr) { + list<Attribute>::iterator it; - for(it = attributes.begin(); it != attributes.end(); it++) { - if(&*it == attr) { - attributes.erase(it); - return; - } - } - } + for (it = attributes.begin(); it != attributes.end(); it++) { + if (&*it == attr) { + attributes.erase(it); + return; + } + } + } } Attribute *AttributeSet::add(AttributeStandard std, ustring name) { - Attribute *attr = NULL; - - if(name == ustring()) - name = Attribute::standard_name(std); - - if(triangle_mesh || subd_mesh) { - switch(std) { - case ATTR_STD_VERTEX_NORMAL: - attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); - break; - case ATTR_STD_FACE_NORMAL: - attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE); - break; - case ATTR_STD_UV: - attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER); - break; - case ATTR_STD_UV_TANGENT: - attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); - break; - case ATTR_STD_UV_TANGENT_SIGN: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); - break; - case ATTR_STD_GENERATED: - case ATTR_STD_POSITION_UNDEFORMED: - case ATTR_STD_POSITION_UNDISPLACED: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); - break; - case ATTR_STD_MOTION_VERTEX_POSITION: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION); - break; - case ATTR_STD_MOTION_VERTEX_NORMAL: - attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX_MOTION); - break; - case ATTR_STD_PTEX_FACE_ID: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE); - break; - case ATTR_STD_PTEX_UV: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); - break; - case ATTR_STD_GENERATED_TRANSFORM: - attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); - break; - case ATTR_STD_VOLUME_DENSITY: - case ATTR_STD_VOLUME_FLAME: - case ATTR_STD_VOLUME_HEAT: - case ATTR_STD_VOLUME_TEMPERATURE: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); - break; - case ATTR_STD_VOLUME_COLOR: - attr = add(name, TypeDesc::TypeColor, ATTR_ELEMENT_VOXEL); - break; - case ATTR_STD_VOLUME_VELOCITY: - attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL); - break; - case ATTR_STD_POINTINESS: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); - break; - default: - assert(0); - break; - } - } - else if(curve_mesh) { - switch(std) { - case ATTR_STD_UV: - attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE); - break; - case ATTR_STD_GENERATED: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); - break; - case ATTR_STD_MOTION_VERTEX_POSITION: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION); - break; - case ATTR_STD_CURVE_INTERCEPT: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); - break; - case ATTR_STD_CURVE_RANDOM: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE); - break; - case ATTR_STD_GENERATED_TRANSFORM: - attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); - break; - case ATTR_STD_POINTINESS: - attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); - break; - default: - assert(0); - break; - } - } - - attr->std = std; - - return attr; + Attribute *attr = NULL; + + if (name == ustring()) + name = Attribute::standard_name(std); + + if (triangle_mesh || subd_mesh) { + switch (std) { + case ATTR_STD_VERTEX_NORMAL: + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); + break; + case ATTR_STD_FACE_NORMAL: + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE); + break; + case ATTR_STD_UV: + attr = add(name, TypeFloat2, ATTR_ELEMENT_CORNER); + break; + case ATTR_STD_UV_TANGENT: + attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); + break; + case ATTR_STD_UV_TANGENT_SIGN: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); + break; + case ATTR_STD_GENERATED: + case ATTR_STD_POSITION_UNDEFORMED: + case ATTR_STD_POSITION_UNDISPLACED: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + break; + case ATTR_STD_MOTION_VERTEX_POSITION: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX_MOTION); + break; + case ATTR_STD_MOTION_VERTEX_NORMAL: + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX_MOTION); + break; + case ATTR_STD_PTEX_FACE_ID: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE); + break; + case ATTR_STD_PTEX_UV: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + break; + case ATTR_STD_GENERATED_TRANSFORM: + attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); + break; + case ATTR_STD_VOLUME_DENSITY: + case ATTR_STD_VOLUME_FLAME: + case ATTR_STD_VOLUME_HEAT: + case ATTR_STD_VOLUME_TEMPERATURE: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); + break; + case ATTR_STD_VOLUME_COLOR: + attr = add(name, TypeDesc::TypeColor, ATTR_ELEMENT_VOXEL); + break; + case ATTR_STD_VOLUME_VELOCITY: + attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_VOXEL); + break; + case ATTR_STD_POINTINESS: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); + break; + default: + assert(0); + break; + } + } + else if (curve_mesh) { + switch (std) { + case ATTR_STD_UV: + attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE); + break; + case ATTR_STD_GENERATED: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); + break; + case ATTR_STD_MOTION_VERTEX_POSITION: + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION); + break; + case ATTR_STD_CURVE_INTERCEPT: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); + break; + case ATTR_STD_CURVE_RANDOM: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE); + break; + case ATTR_STD_GENERATED_TRANSFORM: + attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH); + break; + case ATTR_STD_POINTINESS: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX); + break; + default: + assert(0); + break; + } + } + + attr->std = std; + + return attr; } Attribute *AttributeSet::find(AttributeStandard std) const { - foreach(const Attribute& attr, attributes) - if(attr.std == std) - return (Attribute*)&attr; + foreach (const Attribute &attr, attributes) + if (attr.std == std) + return (Attribute *)&attr; - return NULL; + return NULL; } void AttributeSet::remove(AttributeStandard std) { - Attribute *attr = find(std); + Attribute *attr = find(std); - if(attr) { - list<Attribute>::iterator it; + if (attr) { + list<Attribute>::iterator it; - for(it = attributes.begin(); it != attributes.end(); it++) { - if(&*it == attr) { - attributes.erase(it); - return; - } - } - } + for (it = attributes.begin(); it != attributes.end(); it++) { + if (&*it == attr) { + attributes.erase(it); + return; + } + } + } } -Attribute *AttributeSet::find(AttributeRequest& req) +Attribute *AttributeSet::find(AttributeRequest &req) { - if(req.std == ATTR_STD_NONE) - return find(req.name); - else - return find(req.std); + if (req.std == ATTR_STD_NONE) + return find(req.name); + else + return find(req.std); } void AttributeSet::remove(Attribute *attribute) { - if(attribute->std == ATTR_STD_NONE) { - remove(attribute->name); - } - else { - remove(attribute->std); - } + if (attribute->std == ATTR_STD_NONE) { + remove(attribute->name); + } + else { + remove(attribute->std); + } } void AttributeSet::resize(bool reserve_only) { - foreach(Attribute& attr, attributes) { - if(triangle_mesh) - attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only); - if(curve_mesh) - attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only); - if(subd_mesh) - attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only); - } + foreach (Attribute &attr, attributes) { + if (triangle_mesh) + attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only); + if (curve_mesh) + attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only); + if (subd_mesh) + attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only); + } } void AttributeSet::clear(bool preserve_voxel_data) { - if(preserve_voxel_data) { - list<Attribute>::iterator it; + if (preserve_voxel_data) { + list<Attribute>::iterator it; - for(it = attributes.begin(); it != attributes.end();) { - if(it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) { - it++; - } - else { - attributes.erase(it++); - } - } - } - else { - attributes.clear(); - } + for (it = attributes.begin(); it != attributes.end();) { + if (it->element == ATTR_ELEMENT_VOXEL || it->std == ATTR_STD_GENERATED_TRANSFORM) { + it++; + } + else { + attributes.erase(it++); + } + } + } + else { + attributes.clear(); + } } /* AttributeRequest */ AttributeRequest::AttributeRequest(ustring name_) { - name = name_; - std = ATTR_STD_NONE; + name = name_; + std = ATTR_STD_NONE; - triangle_type = TypeDesc::TypeFloat; - triangle_desc.element = ATTR_ELEMENT_NONE; - triangle_desc.offset = 0; - triangle_desc.type = NODE_ATTR_FLOAT; + triangle_type = TypeDesc::TypeFloat; + triangle_desc.element = ATTR_ELEMENT_NONE; + triangle_desc.offset = 0; + triangle_desc.type = NODE_ATTR_FLOAT; - curve_type = TypeDesc::TypeFloat; - curve_desc.element = ATTR_ELEMENT_NONE; - curve_desc.offset = 0; - curve_desc.type = NODE_ATTR_FLOAT; + curve_type = TypeDesc::TypeFloat; + curve_desc.element = ATTR_ELEMENT_NONE; + curve_desc.offset = 0; + curve_desc.type = NODE_ATTR_FLOAT; - subd_type = TypeDesc::TypeFloat; - subd_desc.element = ATTR_ELEMENT_NONE; - subd_desc.offset = 0; - subd_desc.type = NODE_ATTR_FLOAT; + subd_type = TypeDesc::TypeFloat; + subd_desc.element = ATTR_ELEMENT_NONE; + subd_desc.offset = 0; + subd_desc.type = NODE_ATTR_FLOAT; } AttributeRequest::AttributeRequest(AttributeStandard std_) { - name = ustring(); - std = std_; + name = ustring(); + std = std_; - triangle_type = TypeDesc::TypeFloat; - triangle_desc.element = ATTR_ELEMENT_NONE; - triangle_desc.offset = 0; - triangle_desc.type = NODE_ATTR_FLOAT; + triangle_type = TypeDesc::TypeFloat; + triangle_desc.element = ATTR_ELEMENT_NONE; + triangle_desc.offset = 0; + triangle_desc.type = NODE_ATTR_FLOAT; - curve_type = TypeDesc::TypeFloat; - curve_desc.element = ATTR_ELEMENT_NONE; - curve_desc.offset = 0; - curve_desc.type = NODE_ATTR_FLOAT; + curve_type = TypeDesc::TypeFloat; + curve_desc.element = ATTR_ELEMENT_NONE; + curve_desc.offset = 0; + curve_desc.type = NODE_ATTR_FLOAT; - subd_type = TypeDesc::TypeFloat; - subd_desc.element = ATTR_ELEMENT_NONE; - subd_desc.offset = 0; - subd_desc.type = NODE_ATTR_FLOAT; + subd_type = TypeDesc::TypeFloat; + subd_desc.element = ATTR_ELEMENT_NONE; + subd_desc.offset = 0; + subd_desc.type = NODE_ATTR_FLOAT; } /* AttributeRequestSet */ @@ -634,101 +631,99 @@ AttributeRequestSet::~AttributeRequestSet() { } -bool AttributeRequestSet::modified(const AttributeRequestSet& other) +bool AttributeRequestSet::modified(const AttributeRequestSet &other) { - if(requests.size() != other.requests.size()) - return true; + if (requests.size() != other.requests.size()) + return true; - for(size_t i = 0; i < requests.size(); i++) { - bool found = false; + for (size_t i = 0; i < requests.size(); i++) { + bool found = false; - for(size_t j = 0; j < requests.size() && !found; j++) - if(requests[i].name == other.requests[j].name && - requests[i].std == other.requests[j].std) - { - found = true; - } + for (size_t j = 0; j < requests.size() && !found; j++) + if (requests[i].name == other.requests[j].name && requests[i].std == other.requests[j].std) { + found = true; + } - if(!found) { - return true; - } - } + if (!found) { + return true; + } + } - return false; + return false; } void AttributeRequestSet::add(ustring name) { - foreach(AttributeRequest& req, requests) { - if(req.name == name) { - return; - } - } + foreach (AttributeRequest &req, requests) { + if (req.name == name) { + return; + } + } - requests.push_back(AttributeRequest(name)); + requests.push_back(AttributeRequest(name)); } void AttributeRequestSet::add(AttributeStandard std) { - foreach(AttributeRequest& req, requests) - if(req.std == std) - return; + foreach (AttributeRequest &req, requests) + if (req.std == std) + return; - requests.push_back(AttributeRequest(std)); + requests.push_back(AttributeRequest(std)); } -void AttributeRequestSet::add(AttributeRequestSet& reqs) +void AttributeRequestSet::add(AttributeRequestSet &reqs) { - foreach(AttributeRequest& req, reqs.requests) { - if(req.std == ATTR_STD_NONE) - add(req.name); - else - add(req.std); - } + foreach (AttributeRequest &req, reqs.requests) { + if (req.std == ATTR_STD_NONE) + add(req.name); + else + add(req.std); + } } void AttributeRequestSet::add_standard(ustring name) { - if(name.empty()) { - return; - } + if (name.empty()) { + return; + } - AttributeStandard std = Attribute::name_standard(name.c_str()); + AttributeStandard std = Attribute::name_standard(name.c_str()); - if(std) { - add(std); - } - else { - add(name); - } + if (std) { + add(std); + } + else { + add(name); + } } bool AttributeRequestSet::find(ustring name) { - foreach(AttributeRequest& req, requests) - if(req.name == name) - return true; + foreach (AttributeRequest &req, requests) + if (req.name == name) + return true; - return false; + return false; } bool AttributeRequestSet::find(AttributeStandard std) { - foreach(AttributeRequest& req, requests) - if(req.std == std) - return true; + foreach (AttributeRequest &req, requests) + if (req.std == std) + return true; - return false; + return false; } size_t AttributeRequestSet::size() { - return requests.size(); + return requests.size(); } void AttributeRequestSet::clear() { - requests.clear(); + requests.clear(); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index ed9e9fe76d6..ebab0fe7f88 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -37,8 +37,8 @@ struct Transform; /* Attributes for voxels are images */ struct VoxelAttribute { - ImageManager *manager; - int slot; + ImageManager *manager; + int slot; }; /* Attribute @@ -47,114 +47,116 @@ struct VoxelAttribute { * Supported types: Float, Color, Vector, Normal, Point */ class Attribute { -public: - ustring name; - AttributeStandard std; - - TypeDesc type; - vector<char> buffer; - AttributeElement element; - uint flags; /* enum AttributeFlag */ - - Attribute() {} - ~Attribute(); - void set(ustring name, TypeDesc type, AttributeElement element); - void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only); - void resize(size_t num_elements); - - size_t data_sizeof() const; - size_t element_size(Mesh *mesh, AttributePrimitive prim) const; - size_t buffer_size(Mesh *mesh, AttributePrimitive prim) const; - - char *data() - { - return (buffer.size())? &buffer[0]: NULL; - } - float2 *data_float2() - { - assert(data_sizeof() == sizeof(float2)); - return (float2*)data(); - } - float3 *data_float3() - { - assert(data_sizeof() == sizeof(float3)); - return (float3*)data(); - } - float4 *data_float4() - { - assert(data_sizeof() == sizeof(float4)); - return (float4*)data(); - } - float *data_float() - { - assert(data_sizeof() == sizeof(float)); - return (float*)data(); - } - uchar4 *data_uchar4() - { - assert(data_sizeof() == sizeof(uchar4)); - return (uchar4*)data(); - } - Transform *data_transform() - { - assert(data_sizeof() == sizeof(Transform)); - return (Transform*)data(); - } - VoxelAttribute *data_voxel() - { - assert(data_sizeof() == sizeof(VoxelAttribute)); - return ( VoxelAttribute*)data(); - } - - const char *data() const - { - return (buffer.size())? &buffer[0]: NULL; - } - const float2 *data_float2() const - { - assert(data_sizeof() == sizeof(float2)); - return (const float2*)data(); - } - const float3 *data_float3() const - { - assert(data_sizeof() == sizeof(float3)); - return (const float3*)data(); - } - const float4 *data_float4() const - { - assert(data_sizeof() == sizeof(float4)); - return (const float4*)data(); - } - const float *data_float() const - { - assert(data_sizeof() == sizeof(float)); - return (const float*)data(); - } - const Transform *data_transform() const - { - assert(data_sizeof() == sizeof(Transform)); - return (const Transform*)data(); - } - const VoxelAttribute *data_voxel() const - { - assert(data_sizeof() == sizeof(VoxelAttribute)); - return (const VoxelAttribute*)data(); - } - - void zero_data(void* dst); - void add_with_weight(void* dst, void* src, float weight); - - void add(const float& f); - void add(const float2& f); - void add(const float3& f); - void add(const uchar4& f); - void add(const Transform& f); - void add(const VoxelAttribute& f); - void add(const char *data); - - static bool same_storage(TypeDesc a, TypeDesc b); - static const char *standard_name(AttributeStandard std); - static AttributeStandard name_standard(const char *name); + public: + ustring name; + AttributeStandard std; + + TypeDesc type; + vector<char> buffer; + AttributeElement element; + uint flags; /* enum AttributeFlag */ + + Attribute() + { + } + ~Attribute(); + void set(ustring name, TypeDesc type, AttributeElement element); + void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only); + void resize(size_t num_elements); + + size_t data_sizeof() const; + size_t element_size(Mesh *mesh, AttributePrimitive prim) const; + size_t buffer_size(Mesh *mesh, AttributePrimitive prim) const; + + char *data() + { + return (buffer.size()) ? &buffer[0] : NULL; + } + float2 *data_float2() + { + assert(data_sizeof() == sizeof(float2)); + return (float2 *)data(); + } + float3 *data_float3() + { + assert(data_sizeof() == sizeof(float3)); + return (float3 *)data(); + } + float4 *data_float4() + { + assert(data_sizeof() == sizeof(float4)); + return (float4 *)data(); + } + float *data_float() + { + assert(data_sizeof() == sizeof(float)); + return (float *)data(); + } + uchar4 *data_uchar4() + { + assert(data_sizeof() == sizeof(uchar4)); + return (uchar4 *)data(); + } + Transform *data_transform() + { + assert(data_sizeof() == sizeof(Transform)); + return (Transform *)data(); + } + VoxelAttribute *data_voxel() + { + assert(data_sizeof() == sizeof(VoxelAttribute)); + return (VoxelAttribute *)data(); + } + + const char *data() const + { + return (buffer.size()) ? &buffer[0] : NULL; + } + const float2 *data_float2() const + { + assert(data_sizeof() == sizeof(float2)); + return (const float2 *)data(); + } + const float3 *data_float3() const + { + assert(data_sizeof() == sizeof(float3)); + return (const float3 *)data(); + } + const float4 *data_float4() const + { + assert(data_sizeof() == sizeof(float4)); + return (const float4 *)data(); + } + const float *data_float() const + { + assert(data_sizeof() == sizeof(float)); + return (const float *)data(); + } + const Transform *data_transform() const + { + assert(data_sizeof() == sizeof(Transform)); + return (const Transform *)data(); + } + const VoxelAttribute *data_voxel() const + { + assert(data_sizeof() == sizeof(VoxelAttribute)); + return (const VoxelAttribute *)data(); + } + + void zero_data(void *dst); + void add_with_weight(void *dst, void *src, float weight); + + void add(const float &f); + void add(const float2 &f); + void add(const float3 &f); + void add(const uchar4 &f); + void add(const Transform &f); + void add(const VoxelAttribute &f); + void add(const char *data); + + static bool same_storage(TypeDesc a, TypeDesc b); + static const char *standard_name(AttributeStandard std); + static AttributeStandard name_standard(const char *name); }; /* Attribute Set @@ -162,29 +164,29 @@ public: * Set of attributes on a mesh. */ class AttributeSet { -public: - Mesh *triangle_mesh; - Mesh *curve_mesh; - Mesh *subd_mesh; - list<Attribute> attributes; + public: + Mesh *triangle_mesh; + Mesh *curve_mesh; + Mesh *subd_mesh; + list<Attribute> attributes; - AttributeSet(); - ~AttributeSet(); + AttributeSet(); + ~AttributeSet(); - Attribute *add(ustring name, TypeDesc type, AttributeElement element); - Attribute *find(ustring name) const; - void remove(ustring name); + Attribute *add(ustring name, TypeDesc type, AttributeElement element); + Attribute *find(ustring name) const; + void remove(ustring name); - Attribute *add(AttributeStandard std, ustring name = ustring()); - Attribute *find(AttributeStandard std) const; - void remove(AttributeStandard std); + Attribute *add(AttributeStandard std, ustring name = ustring()); + Attribute *find(AttributeStandard std) const; + void remove(AttributeStandard std); - Attribute *find(AttributeRequest& req); + Attribute *find(AttributeRequest &req); - void remove(Attribute *attribute); + void remove(Attribute *attribute); - void resize(bool reserve_only = false); - void clear(bool preserve_voxel_data = false); + void resize(bool reserve_only = false); + void clear(bool preserve_voxel_data = false); }; /* AttributeRequest @@ -194,16 +196,16 @@ public: * The attribute is found either by name or by standard attribute type. */ class AttributeRequest { -public: - ustring name; - AttributeStandard std; + public: + ustring name; + AttributeStandard std; - /* temporary variables used by MeshManager */ - TypeDesc triangle_type, curve_type, subd_type; - AttributeDescriptor triangle_desc, curve_desc, subd_desc; + /* temporary variables used by MeshManager */ + TypeDesc triangle_type, curve_type, subd_type; + AttributeDescriptor triangle_desc, curve_desc, subd_desc; - explicit AttributeRequest(ustring name_); - explicit AttributeRequest(AttributeStandard std); + explicit AttributeRequest(ustring name_); + explicit AttributeRequest(AttributeStandard std); }; /* AttributeRequestSet @@ -211,26 +213,26 @@ public: * Set of attributes requested by a shader. */ class AttributeRequestSet { -public: - vector<AttributeRequest> requests; + public: + vector<AttributeRequest> requests; - AttributeRequestSet(); - ~AttributeRequestSet(); + AttributeRequestSet(); + ~AttributeRequestSet(); - void add(ustring name); - void add(AttributeStandard std); - void add(AttributeRequestSet& reqs); - void add_standard(ustring name); + void add(ustring name); + void add(AttributeStandard std); + void add(AttributeRequestSet &reqs); + void add_standard(ustring name); - bool find(ustring name); - bool find(AttributeStandard std); + bool find(ustring name); + bool find(AttributeStandard std); - size_t size(); - void clear(); + size_t size(); + void clear(); - bool modified(const AttributeRequestSet& other); + bool modified(const AttributeRequestSet &other); }; CCL_NAMESPACE_END -#endif /* __ATTRIBUTE_H__ */ +#endif /* __ATTRIBUTE_H__ */ diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index d8a49bf6a5e..b32cc55903d 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -30,28 +30,27 @@ CCL_NAMESPACE_BEGIN NODE_DEFINE(Background) { - NodeType* type = NodeType::add("background", create); + NodeType *type = NodeType::add("background", create); - SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f); - SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX); + SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f); + SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX); - SOCKET_BOOLEAN(use_shader, "Use Shader", true); - SOCKET_BOOLEAN(use_ao, "Use AO", false); - SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY); + SOCKET_BOOLEAN(use_shader, "Use Shader", true); + SOCKET_BOOLEAN(use_ao, "Use AO", false); + SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY); - SOCKET_BOOLEAN(transparent, "Transparent", false); - SOCKET_BOOLEAN(transparent_glass, "Transparent Glass", false); - SOCKET_FLOAT(transparent_roughness_threshold, "Transparent Roughness Threshold", 0.0f); + SOCKET_BOOLEAN(transparent, "Transparent", false); + SOCKET_BOOLEAN(transparent_glass, "Transparent Glass", false); + SOCKET_FLOAT(transparent_roughness_threshold, "Transparent Roughness Threshold", 0.0f); - SOCKET_NODE(shader, "Shader", &Shader::node_type); + SOCKET_NODE(shader, "Shader", &Shader::node_type); - return type; + return type; } -Background::Background() -: Node(node_type) +Background::Background() : Node(node_type) { - need_update = true; + need_update = true; } Background::~Background() @@ -60,78 +59,79 @@ Background::~Background() void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene) { - if(!need_update) - return; - - device_free(device, dscene); - - Shader *bg_shader = shader; - - if(use_shader) { - if(!bg_shader) - bg_shader = scene->default_background; - } - else - bg_shader = scene->default_empty; - - /* set shader index and transparent option */ - KernelBackground *kbackground = &dscene->data.background; - - kbackground->ao_factor = (use_ao)? ao_factor: 0.0f; - kbackground->ao_bounces_factor = ao_factor; - kbackground->ao_distance = ao_distance; - - kbackground->transparent = transparent; - kbackground->surface_shader = scene->shader_manager->get_shader_id(bg_shader); - - if(transparent && transparent_glass) { - /* Square twice, once for principled BSDF convention, and once for - * faster comparison in kernel with anisotropic roughness. */ - kbackground->transparent_roughness_squared_threshold = sqr(sqr(transparent_roughness_threshold)); - } - else { - kbackground->transparent_roughness_squared_threshold = -1.0f; - } - - if(bg_shader->has_volume) - kbackground->volume_shader = kbackground->surface_shader; - else - kbackground->volume_shader = SHADER_NONE; - - /* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */ - if(bg_shader->graph->nodes.size() <= 1) { - kbackground->surface_shader |= SHADER_EXCLUDE_ANY; - } - /* Background present, check visibilities */ - else { - if(!(visibility & PATH_RAY_DIFFUSE)) - kbackground->surface_shader |= SHADER_EXCLUDE_DIFFUSE; - if(!(visibility & PATH_RAY_GLOSSY)) - kbackground->surface_shader |= SHADER_EXCLUDE_GLOSSY; - if(!(visibility & PATH_RAY_TRANSMIT)) - kbackground->surface_shader |= SHADER_EXCLUDE_TRANSMIT; - if(!(visibility & PATH_RAY_VOLUME_SCATTER)) - kbackground->surface_shader |= SHADER_EXCLUDE_SCATTER; - if(!(visibility & PATH_RAY_CAMERA)) - kbackground->surface_shader |= SHADER_EXCLUDE_CAMERA; - } - - need_update = false; + if (!need_update) + return; + + device_free(device, dscene); + + Shader *bg_shader = shader; + + if (use_shader) { + if (!bg_shader) + bg_shader = scene->default_background; + } + else + bg_shader = scene->default_empty; + + /* set shader index and transparent option */ + KernelBackground *kbackground = &dscene->data.background; + + kbackground->ao_factor = (use_ao) ? ao_factor : 0.0f; + kbackground->ao_bounces_factor = ao_factor; + kbackground->ao_distance = ao_distance; + + kbackground->transparent = transparent; + kbackground->surface_shader = scene->shader_manager->get_shader_id(bg_shader); + + if (transparent && transparent_glass) { + /* Square twice, once for principled BSDF convention, and once for + * faster comparison in kernel with anisotropic roughness. */ + kbackground->transparent_roughness_squared_threshold = sqr( + sqr(transparent_roughness_threshold)); + } + else { + kbackground->transparent_roughness_squared_threshold = -1.0f; + } + + if (bg_shader->has_volume) + kbackground->volume_shader = kbackground->surface_shader; + else + kbackground->volume_shader = SHADER_NONE; + + /* No background node, make world shader invisible to all rays, to skip evaluation in kernel. */ + if (bg_shader->graph->nodes.size() <= 1) { + kbackground->surface_shader |= SHADER_EXCLUDE_ANY; + } + /* Background present, check visibilities */ + else { + if (!(visibility & PATH_RAY_DIFFUSE)) + kbackground->surface_shader |= SHADER_EXCLUDE_DIFFUSE; + if (!(visibility & PATH_RAY_GLOSSY)) + kbackground->surface_shader |= SHADER_EXCLUDE_GLOSSY; + if (!(visibility & PATH_RAY_TRANSMIT)) + kbackground->surface_shader |= SHADER_EXCLUDE_TRANSMIT; + if (!(visibility & PATH_RAY_VOLUME_SCATTER)) + kbackground->surface_shader |= SHADER_EXCLUDE_SCATTER; + if (!(visibility & PATH_RAY_CAMERA)) + kbackground->surface_shader |= SHADER_EXCLUDE_CAMERA; + } + + need_update = false; } void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/) { } -bool Background::modified(const Background& background) +bool Background::modified(const Background &background) { - return !Node::equals(background); + return !Node::equals(background); } void Background::tag_update(Scene *scene) { - scene->integrator->tag_update(scene); - need_update = true; + scene->integrator->tag_update(scene); + need_update = true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h index 17c3eaaaaf5..020db7bf6aa 100644 --- a/intern/cycles/render/background.h +++ b/intern/cycles/render/background.h @@ -29,34 +29,34 @@ class Scene; class Shader; class Background : public Node { -public: - NODE_DECLARE + public: + NODE_DECLARE - float ao_factor; - float ao_distance; + float ao_factor; + float ao_distance; - bool use_shader; - bool use_ao; + bool use_shader; + bool use_ao; - uint visibility; - Shader *shader; + uint visibility; + Shader *shader; - bool transparent; - bool transparent_glass; - float transparent_roughness_threshold; + bool transparent; + bool transparent_glass; + float transparent_roughness_threshold; - bool need_update; + bool need_update; - Background(); - ~Background(); + Background(); + ~Background(); - void device_update(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene); + void device_update(Device *device, DeviceScene *dscene, Scene *scene); + void device_free(Device *device, DeviceScene *dscene); - bool modified(const Background& background); - void tag_update(Scene *scene); + bool modified(const Background &background); + void tag_update(Scene *scene); }; CCL_NAMESPACE_END -#endif /* __BACKGROUND_H__ */ +#endif /* __BACKGROUND_H__ */ diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index 927e04abc7f..73893921500 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -24,221 +24,220 @@ CCL_NAMESPACE_BEGIN -BakeData::BakeData(const int object, const size_t tri_offset, const size_t num_pixels): -m_object(object), -m_tri_offset(tri_offset), -m_num_pixels(num_pixels) +BakeData::BakeData(const int object, const size_t tri_offset, const size_t num_pixels) + : m_object(object), m_tri_offset(tri_offset), m_num_pixels(num_pixels) { - m_primitive.resize(num_pixels); - m_u.resize(num_pixels); - m_v.resize(num_pixels); - m_dudx.resize(num_pixels); - m_dudy.resize(num_pixels); - m_dvdx.resize(num_pixels); - m_dvdy.resize(num_pixels); + m_primitive.resize(num_pixels); + m_u.resize(num_pixels); + m_v.resize(num_pixels); + m_dudx.resize(num_pixels); + m_dudy.resize(num_pixels); + m_dvdx.resize(num_pixels); + m_dvdy.resize(num_pixels); } BakeData::~BakeData() { - m_primitive.clear(); - m_u.clear(); - m_v.clear(); - m_dudx.clear(); - m_dudy.clear(); - m_dvdx.clear(); - m_dvdy.clear(); + m_primitive.clear(); + m_u.clear(); + m_v.clear(); + m_dudx.clear(); + m_dudy.clear(); + m_dvdx.clear(); + m_dvdy.clear(); } void BakeData::set(int i, int prim, float uv[2], float dudx, float dudy, float dvdx, float dvdy) { - m_primitive[i] = (prim == -1 ? -1 : m_tri_offset + prim); - m_u[i] = uv[0]; - m_v[i] = uv[1]; - m_dudx[i] = dudx; - m_dudy[i] = dudy; - m_dvdx[i] = dvdx; - m_dvdy[i] = dvdy; + m_primitive[i] = (prim == -1 ? -1 : m_tri_offset + prim); + m_u[i] = uv[0]; + m_v[i] = uv[1]; + m_dudx[i] = dudx; + m_dudy[i] = dudy; + m_dvdx[i] = dvdx; + m_dvdy[i] = dvdy; } void BakeData::set_null(int i) { - m_primitive[i] = -1; + m_primitive[i] = -1; } int BakeData::object() { - return m_object; + return m_object; } size_t BakeData::size() { - return m_num_pixels; + return m_num_pixels; } bool BakeData::is_valid(int i) { - return m_primitive[i] != -1; + return m_primitive[i] != -1; } uint4 BakeData::data(int i) { - return make_uint4( - m_object, - m_primitive[i], - __float_as_int(m_u[i]), - __float_as_int(m_v[i]) - ); + return make_uint4(m_object, m_primitive[i], __float_as_int(m_u[i]), __float_as_int(m_v[i])); } uint4 BakeData::differentials(int i) { - return make_uint4( - __float_as_int(m_dudx[i]), - __float_as_int(m_dudy[i]), - __float_as_int(m_dvdx[i]), - __float_as_int(m_dvdy[i]) - ); + return make_uint4(__float_as_int(m_dudx[i]), + __float_as_int(m_dudy[i]), + __float_as_int(m_dvdx[i]), + __float_as_int(m_dvdy[i])); } BakeManager::BakeManager() { - m_bake_data = NULL; - m_is_baking = false; - need_update = true; - m_shader_limit = 512 * 512; + m_bake_data = NULL; + m_is_baking = false; + need_update = true; + m_shader_limit = 512 * 512; } BakeManager::~BakeManager() { - if(m_bake_data) - delete m_bake_data; + if (m_bake_data) + delete m_bake_data; } bool BakeManager::get_baking() { - return m_is_baking; + return m_is_baking; } void BakeManager::set_baking(const bool value) { - m_is_baking = value; + m_is_baking = value; } BakeData *BakeManager::init(const int object, const size_t tri_offset, const size_t num_pixels) { - m_bake_data = new BakeData(object, tri_offset, num_pixels); - return m_bake_data; + m_bake_data = new BakeData(object, tri_offset, num_pixels); + return m_bake_data; } void BakeManager::set_shader_limit(const size_t x, const size_t y) { - m_shader_limit = x * y; - m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit)/log(2))); + m_shader_limit = x * y; + m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit) / log(2))); } -bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, const int pass_filter, BakeData *bake_data, float result[]) +bool BakeManager::bake(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress, + ShaderEvalType shader_type, + const int pass_filter, + BakeData *bake_data, + float result[]) { - size_t num_pixels = bake_data->size(); - - int num_samples = aa_samples(scene, bake_data, shader_type); - - /* calculate the total pixel samples for the progress bar */ - total_pixel_samples = 0; - for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) { - size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit); - total_pixel_samples += shader_size * num_samples; - } - progress.reset_sample(); - progress.set_total_pixel_samples(total_pixel_samples); - - /* needs to be up to date for baking specific AA samples */ - dscene->data.integrator.aa_samples = num_samples; - device->const_copy_to("__data", &dscene->data, sizeof(dscene->data)); - - for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) { - size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit); - - /* setup input for device task */ - device_vector<uint4> d_input(device, "bake_input", MEM_READ_ONLY); - uint4 *d_input_data = d_input.alloc(shader_size * 2); - size_t d_input_size = 0; - - for(size_t i = shader_offset; i < (shader_offset + shader_size); i++) { - d_input_data[d_input_size++] = bake_data->data(i); - d_input_data[d_input_size++] = bake_data->differentials(i); - } - - if(d_input_size == 0) { - m_is_baking = false; - return false; - } - - /* run device task */ - device_vector<float4> d_output(device, "bake_output", MEM_READ_WRITE); - d_output.alloc(shader_size); - d_output.zero_to_device(); - d_input.copy_to_device(); - - DeviceTask task(DeviceTask::SHADER); - task.shader_input = d_input.device_pointer; - task.shader_output = d_output.device_pointer; - task.shader_eval_type = shader_type; - task.shader_filter = pass_filter; - task.shader_x = 0; - task.offset = shader_offset; - task.shader_w = d_output.size(); - task.num_samples = num_samples; - task.get_cancel = function_bind(&Progress::get_cancel, &progress); - task.update_progress_sample = function_bind(&Progress::add_samples_update, &progress, _1, _2); - - device->task_add(task); - device->task_wait(); - - if(progress.get_cancel()) { - d_input.free(); - d_output.free(); - m_is_baking = false; - return false; - } - - d_output.copy_from_device(0, 1, d_output.size()); - d_input.free(); - - /* read result */ - int k = 0; - - float4 *offset = d_output.data(); - - size_t depth = 4; - for(size_t i=shader_offset; i < (shader_offset + shader_size); i++) { - size_t index = i * depth; - float4 out = offset[k++]; - - if(bake_data->is_valid(i)) { - for(size_t j=0; j < 4; j++) { - result[index + j] = out[j]; - } - } - } - - d_output.free(); - } - - m_is_baking = false; - return true; + size_t num_pixels = bake_data->size(); + + int num_samples = aa_samples(scene, bake_data, shader_type); + + /* calculate the total pixel samples for the progress bar */ + total_pixel_samples = 0; + for (size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) { + size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit); + total_pixel_samples += shader_size * num_samples; + } + progress.reset_sample(); + progress.set_total_pixel_samples(total_pixel_samples); + + /* needs to be up to date for baking specific AA samples */ + dscene->data.integrator.aa_samples = num_samples; + device->const_copy_to("__data", &dscene->data, sizeof(dscene->data)); + + for (size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) { + size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit); + + /* setup input for device task */ + device_vector<uint4> d_input(device, "bake_input", MEM_READ_ONLY); + uint4 *d_input_data = d_input.alloc(shader_size * 2); + size_t d_input_size = 0; + + for (size_t i = shader_offset; i < (shader_offset + shader_size); i++) { + d_input_data[d_input_size++] = bake_data->data(i); + d_input_data[d_input_size++] = bake_data->differentials(i); + } + + if (d_input_size == 0) { + m_is_baking = false; + return false; + } + + /* run device task */ + device_vector<float4> d_output(device, "bake_output", MEM_READ_WRITE); + d_output.alloc(shader_size); + d_output.zero_to_device(); + d_input.copy_to_device(); + + DeviceTask task(DeviceTask::SHADER); + task.shader_input = d_input.device_pointer; + task.shader_output = d_output.device_pointer; + task.shader_eval_type = shader_type; + task.shader_filter = pass_filter; + task.shader_x = 0; + task.offset = shader_offset; + task.shader_w = d_output.size(); + task.num_samples = num_samples; + task.get_cancel = function_bind(&Progress::get_cancel, &progress); + task.update_progress_sample = function_bind(&Progress::add_samples_update, &progress, _1, _2); + + device->task_add(task); + device->task_wait(); + + if (progress.get_cancel()) { + d_input.free(); + d_output.free(); + m_is_baking = false; + return false; + } + + d_output.copy_from_device(0, 1, d_output.size()); + d_input.free(); + + /* read result */ + int k = 0; + + float4 *offset = d_output.data(); + + size_t depth = 4; + for (size_t i = shader_offset; i < (shader_offset + shader_size); i++) { + size_t index = i * depth; + float4 out = offset[k++]; + + if (bake_data->is_valid(i)) { + for (size_t j = 0; j < 4; j++) { + result[index + j] = out[j]; + } + } + } + + d_output.free(); + } + + m_is_baking = false; + return true; } void BakeManager::device_update(Device * /*device*/, DeviceScene * /*dscene*/, Scene * /*scene*/, - Progress& progress) + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - if(progress.get_cancel()) return; + if (progress.get_cancel()) + return; - need_update = false; + need_update = false; } void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/) @@ -247,51 +246,52 @@ void BakeManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/) int BakeManager::aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type) { - if(type == SHADER_EVAL_UV || type == SHADER_EVAL_ROUGHNESS) { - return 1; - } - else if(type == SHADER_EVAL_NORMAL) { - /* Only antialias normal if mesh has bump mapping. */ - Object *object = scene->objects[bake_data->object()]; - - if(object->mesh) { - foreach(Shader *shader, object->mesh->used_shaders) { - if(shader->has_bump) { - return scene->integrator->aa_samples; - } - } - } - - return 1; - } - else { - return scene->integrator->aa_samples; - } + if (type == SHADER_EVAL_UV || type == SHADER_EVAL_ROUGHNESS) { + return 1; + } + else if (type == SHADER_EVAL_NORMAL) { + /* Only antialias normal if mesh has bump mapping. */ + Object *object = scene->objects[bake_data->object()]; + + if (object->mesh) { + foreach (Shader *shader, object->mesh->used_shaders) { + if (shader->has_bump) { + return scene->integrator->aa_samples; + } + } + } + + return 1; + } + else { + return scene->integrator->aa_samples; + } } /* Keep it synced with kernel_bake.h logic */ int BakeManager::shader_type_to_pass_filter(ShaderEvalType type, const int pass_filter) { - const int component_flags = pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT | BAKE_FILTER_COLOR); - - switch(type) { - case SHADER_EVAL_AO: - return BAKE_FILTER_AO; - case SHADER_EVAL_SHADOW: - return BAKE_FILTER_DIRECT; - case SHADER_EVAL_DIFFUSE: - return BAKE_FILTER_DIFFUSE | component_flags; - case SHADER_EVAL_GLOSSY: - return BAKE_FILTER_GLOSSY | component_flags; - case SHADER_EVAL_TRANSMISSION: - return BAKE_FILTER_TRANSMISSION | component_flags; - case SHADER_EVAL_SUBSURFACE: - return BAKE_FILTER_SUBSURFACE | component_flags; - case SHADER_EVAL_COMBINED: - return pass_filter; - default: - return 0; - } + const int component_flags = pass_filter & + (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT | BAKE_FILTER_COLOR); + + switch (type) { + case SHADER_EVAL_AO: + return BAKE_FILTER_AO; + case SHADER_EVAL_SHADOW: + return BAKE_FILTER_DIRECT; + case SHADER_EVAL_DIFFUSE: + return BAKE_FILTER_DIFFUSE | component_flags; + case SHADER_EVAL_GLOSSY: + return BAKE_FILTER_GLOSSY | component_flags; + case SHADER_EVAL_TRANSMISSION: + return BAKE_FILTER_TRANSMISSION | component_flags; + case SHADER_EVAL_SUBSURFACE: + return BAKE_FILTER_SUBSURFACE | component_flags; + case SHADER_EVAL_COMBINED: + return pass_filter; + default: + return 0; + } } CCL_NAMESPACE_END diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h index fce8f2fa606..88537623efb 100644 --- a/intern/cycles/render/bake.h +++ b/intern/cycles/render/bake.h @@ -26,61 +26,68 @@ CCL_NAMESPACE_BEGIN class BakeData { -public: - BakeData(const int object, const size_t tri_offset, const size_t num_pixels); - ~BakeData(); - - void set(int i, int prim, float uv[2], float dudx, float dudy, float dvdx, float dvdy); - void set_null(int i); - int object(); - size_t size(); - uint4 data(int i); - uint4 differentials(int i); - bool is_valid(int i); - -private: - int m_object; - size_t m_tri_offset; - size_t m_num_pixels; - vector<int>m_primitive; - vector<float>m_u; - vector<float>m_v; - vector<float>m_dudx; - vector<float>m_dudy; - vector<float>m_dvdx; - vector<float>m_dvdy; + public: + BakeData(const int object, const size_t tri_offset, const size_t num_pixels); + ~BakeData(); + + void set(int i, int prim, float uv[2], float dudx, float dudy, float dvdx, float dvdy); + void set_null(int i); + int object(); + size_t size(); + uint4 data(int i); + uint4 differentials(int i); + bool is_valid(int i); + + private: + int m_object; + size_t m_tri_offset; + size_t m_num_pixels; + vector<int> m_primitive; + vector<float> m_u; + vector<float> m_v; + vector<float> m_dudx; + vector<float> m_dudy; + vector<float> m_dvdx; + vector<float> m_dvdy; }; class BakeManager { -public: - BakeManager(); - ~BakeManager(); + public: + BakeManager(); + ~BakeManager(); - bool get_baking(); - void set_baking(const bool value); + bool get_baking(); + void set_baking(const bool value); - BakeData *init(const int object, const size_t tri_offset, const size_t num_pixels); + BakeData *init(const int object, const size_t tri_offset, const size_t num_pixels); - void set_shader_limit(const size_t x, const size_t y); + void set_shader_limit(const size_t x, const size_t y); - bool bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, const int pass_filter, BakeData *bake_data, float result[]); + bool bake(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress, + ShaderEvalType shader_type, + const int pass_filter, + BakeData *bake_data, + float result[]); - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_free(Device *device, DeviceScene *dscene); + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free(Device *device, DeviceScene *dscene); - static int shader_type_to_pass_filter(ShaderEvalType type, const int pass_filter); - static int aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type); + static int shader_type_to_pass_filter(ShaderEvalType type, const int pass_filter); + static int aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType type); - bool need_update; + bool need_update; - size_t total_pixel_samples; + size_t total_pixel_samples; -private: - BakeData *m_bake_data; - bool m_is_baking; - size_t m_shader_limit; + private: + BakeData *m_bake_data; + bool m_is_baking; + size_t m_shader_limit; }; CCL_NAMESPACE_END -#endif /* __BAKE_H__ */ +#endif /* __BAKE_H__ */ diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 678105aeeb1..5405aaefc1d 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -32,455 +32,458 @@ CCL_NAMESPACE_BEGIN BufferParams::BufferParams() { - width = 0; - height = 0; + width = 0; + height = 0; - full_x = 0; - full_y = 0; - full_width = 0; - full_height = 0; + full_x = 0; + full_y = 0; + full_width = 0; + full_height = 0; - denoising_data_pass = false; - denoising_clean_pass = false; - denoising_prefiltered_pass = false; + denoising_data_pass = false; + denoising_clean_pass = false; + denoising_prefiltered_pass = false; - Pass::add(PASS_COMBINED, passes); + Pass::add(PASS_COMBINED, passes); } -void BufferParams::get_offset_stride(int& offset, int& stride) +void BufferParams::get_offset_stride(int &offset, int &stride) { - offset = -(full_x + full_y*width); - stride = width; + offset = -(full_x + full_y * width); + stride = width; } -bool BufferParams::modified(const BufferParams& params) +bool BufferParams::modified(const BufferParams ¶ms) { - return !(full_x == params.full_x - && full_y == params.full_y - && width == params.width - && height == params.height - && full_width == params.full_width - && full_height == params.full_height - && Pass::equals(passes, params.passes)); + return !(full_x == params.full_x && full_y == params.full_y && width == params.width && + height == params.height && full_width == params.full_width && + full_height == params.full_height && Pass::equals(passes, params.passes)); } int BufferParams::get_passes_size() { - int size = 0; + int size = 0; - for(size_t i = 0; i < passes.size(); i++) - size += passes[i].components; + for (size_t i = 0; i < passes.size(); i++) + size += passes[i].components; - if(denoising_data_pass) { - size += DENOISING_PASS_SIZE_BASE; - if(denoising_clean_pass) size += DENOISING_PASS_SIZE_CLEAN; - if(denoising_prefiltered_pass) size += DENOISING_PASS_SIZE_PREFILTERED; - } + if (denoising_data_pass) { + size += DENOISING_PASS_SIZE_BASE; + if (denoising_clean_pass) + size += DENOISING_PASS_SIZE_CLEAN; + if (denoising_prefiltered_pass) + size += DENOISING_PASS_SIZE_PREFILTERED; + } - return align_up(size, 4); + return align_up(size, 4); } int BufferParams::get_denoising_offset() { - int offset = 0; + int offset = 0; - for(size_t i = 0; i < passes.size(); i++) - offset += passes[i].components; + for (size_t i = 0; i < passes.size(); i++) + offset += passes[i].components; - return offset; + return offset; } int BufferParams::get_denoising_prefiltered_offset() { - assert(denoising_prefiltered_pass); + assert(denoising_prefiltered_pass); - int offset = get_denoising_offset(); + int offset = get_denoising_offset(); - offset += DENOISING_PASS_SIZE_BASE; - if(denoising_clean_pass) { - offset += DENOISING_PASS_SIZE_CLEAN; - } + offset += DENOISING_PASS_SIZE_BASE; + if (denoising_clean_pass) { + offset += DENOISING_PASS_SIZE_CLEAN; + } - return offset; + return offset; } /* Render Buffer Task */ RenderTile::RenderTile() { - x = 0; - y = 0; - w = 0; - h = 0; + x = 0; + y = 0; + w = 0; + h = 0; - sample = 0; - start_sample = 0; - num_samples = 0; - resolution = 0; + sample = 0; + start_sample = 0; + num_samples = 0; + resolution = 0; - offset = 0; - stride = 0; + offset = 0; + stride = 0; - buffer = 0; + buffer = 0; - buffers = NULL; + buffers = NULL; } /* Render Buffers */ RenderBuffers::RenderBuffers(Device *device) -: buffer(device, "RenderBuffers", MEM_READ_WRITE), - map_neighbor_copied(false), render_time(0.0f) + : buffer(device, "RenderBuffers", MEM_READ_WRITE), + map_neighbor_copied(false), + render_time(0.0f) { } RenderBuffers::~RenderBuffers() { - buffer.free(); + buffer.free(); } -void RenderBuffers::reset(BufferParams& params_) +void RenderBuffers::reset(BufferParams ¶ms_) { - params = params_; + params = params_; - /* re-allocate buffer */ - buffer.alloc(params.width*params.height*params.get_passes_size()); - buffer.zero_to_device(); + /* re-allocate buffer */ + buffer.alloc(params.width * params.height * params.get_passes_size()); + buffer.zero_to_device(); } void RenderBuffers::zero() { - buffer.zero_to_device(); + buffer.zero_to_device(); } bool RenderBuffers::copy_from_device() { - if(!buffer.device_pointer) - return false; + if (!buffer.device_pointer) + return false; - buffer.copy_from_device(0, params.width * params.get_passes_size(), params.height); + buffer.copy_from_device(0, params.width * params.get_passes_size(), params.height); - return true; + return true; } -bool RenderBuffers::get_denoising_pass_rect(int type, float exposure, int sample, int components, float *pixels) +bool RenderBuffers::get_denoising_pass_rect( + int type, float exposure, int sample, int components, float *pixels) { - if(buffer.data() == NULL) { - return false; - } - - float scale = 1.0f; - float alpha_scale = 1.0f/sample; - if(type == DENOISING_PASS_PREFILTERED_COLOR || - type == DENOISING_PASS_CLEAN || - type == DENOISING_PASS_PREFILTERED_INTENSITY) { - scale *= exposure; - } - else if(type == DENOISING_PASS_PREFILTERED_VARIANCE) { - scale *= exposure*exposure * (sample - 1); - } - - int offset; - if(type == DENOISING_PASS_CLEAN) { - /* The clean pass isn't changed by prefiltering, so we use the original one there. */ - offset = type + params.get_denoising_offset(); - scale /= sample; - } - else if (type == DENOISING_PASS_PREFILTERED_COLOR && !params.denoising_prefiltered_pass) { - /* If we're not saving the prefiltering result, return the original noisy pass. */ - offset = params.get_denoising_offset() + DENOISING_PASS_COLOR; - scale /= sample; - } - else { - offset = type + params.get_denoising_prefiltered_offset(); - } - - int pass_stride = params.get_passes_size(); - int size = params.width*params.height; - - float *in = buffer.data() + offset; - - if(components == 1) { - for(int i = 0; i < size; i++, in += pass_stride, pixels++) { - pixels[0] = in[0]*scale; - } - } - else if(components == 3) { - for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) { - pixels[0] = in[0]*scale; - pixels[1] = in[1]*scale; - pixels[2] = in[2]*scale; - } - } - else if(components == 4) { - /* Since the alpha channel is not involved in denoising, output the Combined alpha channel. */ - assert(params.passes[0].type == PASS_COMBINED); - float *in_combined = buffer.data(); - - for(int i = 0; i < size; i++, in += pass_stride, in_combined += pass_stride, pixels += 4) { - pixels[0] = in[0]*scale; - pixels[1] = in[1]*scale; - pixels[2] = in[2]*scale; - pixels[3] = saturate(in_combined[3]*alpha_scale); - } - } - else { - return false; - } - - return true; + if (buffer.data() == NULL) { + return false; + } + + float scale = 1.0f; + float alpha_scale = 1.0f / sample; + if (type == DENOISING_PASS_PREFILTERED_COLOR || type == DENOISING_PASS_CLEAN || + type == DENOISING_PASS_PREFILTERED_INTENSITY) { + scale *= exposure; + } + else if (type == DENOISING_PASS_PREFILTERED_VARIANCE) { + scale *= exposure * exposure * (sample - 1); + } + + int offset; + if (type == DENOISING_PASS_CLEAN) { + /* The clean pass isn't changed by prefiltering, so we use the original one there. */ + offset = type + params.get_denoising_offset(); + scale /= sample; + } + else if (type == DENOISING_PASS_PREFILTERED_COLOR && !params.denoising_prefiltered_pass) { + /* If we're not saving the prefiltering result, return the original noisy pass. */ + offset = params.get_denoising_offset() + DENOISING_PASS_COLOR; + scale /= sample; + } + else { + offset = type + params.get_denoising_prefiltered_offset(); + } + + int pass_stride = params.get_passes_size(); + int size = params.width * params.height; + + float *in = buffer.data() + offset; + + if (components == 1) { + for (int i = 0; i < size; i++, in += pass_stride, pixels++) { + pixels[0] = in[0] * scale; + } + } + else if (components == 3) { + for (int i = 0; i < size; i++, in += pass_stride, pixels += 3) { + pixels[0] = in[0] * scale; + pixels[1] = in[1] * scale; + pixels[2] = in[2] * scale; + } + } + else if (components == 4) { + /* Since the alpha channel is not involved in denoising, output the Combined alpha channel. */ + assert(params.passes[0].type == PASS_COMBINED); + float *in_combined = buffer.data(); + + for (int i = 0; i < size; i++, in += pass_stride, in_combined += pass_stride, pixels += 4) { + pixels[0] = in[0] * scale; + pixels[1] = in[1] * scale; + pixels[2] = in[2] * scale; + pixels[3] = saturate(in_combined[3] * alpha_scale); + } + } + else { + return false; + } + + return true; } -bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels, const string &name) +bool RenderBuffers::get_pass_rect( + PassType type, float exposure, int sample, int components, float *pixels, const string &name) { - if(buffer.data() == NULL) { - return false; - } - - int pass_offset = 0; - - for(size_t j = 0; j < params.passes.size(); j++) { - Pass& pass = params.passes[j]; - - if(pass.type != type) { - pass_offset += pass.components; - continue; - } - - /* Tell Cryptomatte passes apart by their name. */ - if(pass.type == PASS_CRYPTOMATTE) { - if(pass.name != name) { - pass_offset += pass.components; - continue; - } - } - - float *in = buffer.data() + pass_offset; - int pass_stride = params.get_passes_size(); - - float scale = (pass.filter)? 1.0f/(float)sample: 1.0f; - float scale_exposure = (pass.exposure)? scale*exposure: scale; - - int size = params.width*params.height; - - if(components == 1 && type == PASS_RENDER_TIME) { - /* Render time is not stored by kernel, but measured per tile. */ - float val = (float) (1000.0 * render_time/(params.width * params.height * sample)); - for(int i = 0; i < size; i++, pixels++) { - pixels[0] = val; - } - } - else if(components == 1) { - assert(pass.components == components); - - /* Scalar */ - if(type == PASS_DEPTH) { - for(int i = 0; i < size; i++, in += pass_stride, pixels++) { - float f = *in; - pixels[0] = (f == 0.0f)? 1e10f: f*scale_exposure; - } - } - else if(type == PASS_MIST) { - for(int i = 0; i < size; i++, in += pass_stride, pixels++) { - float f = *in; - pixels[0] = saturate(f*scale_exposure); - } - } + if (buffer.data() == NULL) { + return false; + } + + int pass_offset = 0; + + for (size_t j = 0; j < params.passes.size(); j++) { + Pass &pass = params.passes[j]; + + if (pass.type != type) { + pass_offset += pass.components; + continue; + } + + /* Tell Cryptomatte passes apart by their name. */ + if (pass.type == PASS_CRYPTOMATTE) { + if (pass.name != name) { + pass_offset += pass.components; + continue; + } + } + + float *in = buffer.data() + pass_offset; + int pass_stride = params.get_passes_size(); + + float scale = (pass.filter) ? 1.0f / (float)sample : 1.0f; + float scale_exposure = (pass.exposure) ? scale * exposure : scale; + + int size = params.width * params.height; + + if (components == 1 && type == PASS_RENDER_TIME) { + /* Render time is not stored by kernel, but measured per tile. */ + float val = (float)(1000.0 * render_time / (params.width * params.height * sample)); + for (int i = 0; i < size; i++, pixels++) { + pixels[0] = val; + } + } + else if (components == 1) { + assert(pass.components == components); + + /* Scalar */ + if (type == PASS_DEPTH) { + for (int i = 0; i < size; i++, in += pass_stride, pixels++) { + float f = *in; + pixels[0] = (f == 0.0f) ? 1e10f : f * scale_exposure; + } + } + else if (type == PASS_MIST) { + for (int i = 0; i < size; i++, in += pass_stride, pixels++) { + float f = *in; + pixels[0] = saturate(f * scale_exposure); + } + } #ifdef WITH_CYCLES_DEBUG - else if(type == PASS_BVH_TRAVERSED_NODES || - type == PASS_BVH_TRAVERSED_INSTANCES || - type == PASS_BVH_INTERSECTIONS || - type == PASS_RAY_BOUNCES) - { - for(int i = 0; i < size; i++, in += pass_stride, pixels++) { - float f = *in; - pixels[0] = f*scale; - } - } + else if (type == PASS_BVH_TRAVERSED_NODES || type == PASS_BVH_TRAVERSED_INSTANCES || + type == PASS_BVH_INTERSECTIONS || type == PASS_RAY_BOUNCES) { + for (int i = 0; i < size; i++, in += pass_stride, pixels++) { + float f = *in; + pixels[0] = f * scale; + } + } #endif - else { - for(int i = 0; i < size; i++, in += pass_stride, pixels++) { - float f = *in; - pixels[0] = f*scale_exposure; - } - } - } - else if(components == 3) { - assert(pass.components == 4); - - /* RGBA */ - if(type == PASS_SHADOW) { - for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) { - float4 f = make_float4(in[0], in[1], in[2], in[3]); - float invw = (f.w > 0.0f)? 1.0f/f.w: 1.0f; - - pixels[0] = f.x*invw; - pixels[1] = f.y*invw; - pixels[2] = f.z*invw; - } - } - else if(pass.divide_type != PASS_NONE) { - /* RGB lighting passes that need to divide out color */ - pass_offset = 0; - for(size_t k = 0; k < params.passes.size(); k++) { - Pass& color_pass = params.passes[k]; - if(color_pass.type == pass.divide_type) - break; - pass_offset += color_pass.components; - } - - float *in_divide = buffer.data() + pass_offset; - - for(int i = 0; i < size; i++, in += pass_stride, in_divide += pass_stride, pixels += 3) { - float3 f = make_float3(in[0], in[1], in[2]); - float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]); - - f = safe_divide_even_color(f*exposure, f_divide); - - pixels[0] = f.x; - pixels[1] = f.y; - pixels[2] = f.z; - } - } - else { - /* RGB/vector */ - for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) { - float3 f = make_float3(in[0], in[1], in[2]); - - pixels[0] = f.x*scale_exposure; - pixels[1] = f.y*scale_exposure; - pixels[2] = f.z*scale_exposure; - } - } - } - else if(components == 4) { - assert(pass.components == components); - - /* RGBA */ - if(type == PASS_SHADOW) { - for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) { - float4 f = make_float4(in[0], in[1], in[2], in[3]); - float invw = (f.w > 0.0f)? 1.0f/f.w: 1.0f; - - pixels[0] = f.x*invw; - pixels[1] = f.y*invw; - pixels[2] = f.z*invw; - pixels[3] = 1.0f; - } - } - else if(type == PASS_MOTION) { - /* need to normalize by number of samples accumulated for motion */ - pass_offset = 0; - for(size_t k = 0; k < params.passes.size(); k++) { - Pass& color_pass = params.passes[k]; - if(color_pass.type == PASS_MOTION_WEIGHT) - break; - pass_offset += color_pass.components; - } - - float *in_weight = buffer.data() + pass_offset; - - for(int i = 0; i < size; i++, in += pass_stride, in_weight += pass_stride, pixels += 4) { - float4 f = make_float4(in[0], in[1], in[2], in[3]); - float w = in_weight[0]; - float invw = (w > 0.0f)? 1.0f/w: 0.0f; - - pixels[0] = f.x*invw; - pixels[1] = f.y*invw; - pixels[2] = f.z*invw; - pixels[3] = f.w*invw; - } - } - else if(type == PASS_CRYPTOMATTE) { - for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) { - float4 f = make_float4(in[0], in[1], in[2], in[3]); - /* x and z contain integer IDs, don't rescale them. - y and w contain matte weights, they get scaled. */ - pixels[0] = f.x; - pixels[1] = f.y * scale; - pixels[2] = f.z; - pixels[3] = f.w * scale; - } - } - else { - for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) { - float4 f = make_float4(in[0], in[1], in[2], in[3]); - - pixels[0] = f.x*scale_exposure; - pixels[1] = f.y*scale_exposure; - pixels[2] = f.z*scale_exposure; - - /* clamp since alpha might be > 1.0 due to russian roulette */ - pixels[3] = saturate(f.w*scale); - } - } - } - - return true; - } - - return false; + else { + for (int i = 0; i < size; i++, in += pass_stride, pixels++) { + float f = *in; + pixels[0] = f * scale_exposure; + } + } + } + else if (components == 3) { + assert(pass.components == 4); + + /* RGBA */ + if (type == PASS_SHADOW) { + for (int i = 0; i < size; i++, in += pass_stride, pixels += 3) { + float4 f = make_float4(in[0], in[1], in[2], in[3]); + float invw = (f.w > 0.0f) ? 1.0f / f.w : 1.0f; + + pixels[0] = f.x * invw; + pixels[1] = f.y * invw; + pixels[2] = f.z * invw; + } + } + else if (pass.divide_type != PASS_NONE) { + /* RGB lighting passes that need to divide out color */ + pass_offset = 0; + for (size_t k = 0; k < params.passes.size(); k++) { + Pass &color_pass = params.passes[k]; + if (color_pass.type == pass.divide_type) + break; + pass_offset += color_pass.components; + } + + float *in_divide = buffer.data() + pass_offset; + + for (int i = 0; i < size; i++, in += pass_stride, in_divide += pass_stride, pixels += 3) { + float3 f = make_float3(in[0], in[1], in[2]); + float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]); + + f = safe_divide_even_color(f * exposure, f_divide); + + pixels[0] = f.x; + pixels[1] = f.y; + pixels[2] = f.z; + } + } + else { + /* RGB/vector */ + for (int i = 0; i < size; i++, in += pass_stride, pixels += 3) { + float3 f = make_float3(in[0], in[1], in[2]); + + pixels[0] = f.x * scale_exposure; + pixels[1] = f.y * scale_exposure; + pixels[2] = f.z * scale_exposure; + } + } + } + else if (components == 4) { + assert(pass.components == components); + + /* RGBA */ + if (type == PASS_SHADOW) { + for (int i = 0; i < size; i++, in += pass_stride, pixels += 4) { + float4 f = make_float4(in[0], in[1], in[2], in[3]); + float invw = (f.w > 0.0f) ? 1.0f / f.w : 1.0f; + + pixels[0] = f.x * invw; + pixels[1] = f.y * invw; + pixels[2] = f.z * invw; + pixels[3] = 1.0f; + } + } + else if (type == PASS_MOTION) { + /* need to normalize by number of samples accumulated for motion */ + pass_offset = 0; + for (size_t k = 0; k < params.passes.size(); k++) { + Pass &color_pass = params.passes[k]; + if (color_pass.type == PASS_MOTION_WEIGHT) + break; + pass_offset += color_pass.components; + } + + float *in_weight = buffer.data() + pass_offset; + + for (int i = 0; i < size; i++, in += pass_stride, in_weight += pass_stride, pixels += 4) { + float4 f = make_float4(in[0], in[1], in[2], in[3]); + float w = in_weight[0]; + float invw = (w > 0.0f) ? 1.0f / w : 0.0f; + + pixels[0] = f.x * invw; + pixels[1] = f.y * invw; + pixels[2] = f.z * invw; + pixels[3] = f.w * invw; + } + } + else if (type == PASS_CRYPTOMATTE) { + for (int i = 0; i < size; i++, in += pass_stride, pixels += 4) { + float4 f = make_float4(in[0], in[1], in[2], in[3]); + /* x and z contain integer IDs, don't rescale them. + y and w contain matte weights, they get scaled. */ + pixels[0] = f.x; + pixels[1] = f.y * scale; + pixels[2] = f.z; + pixels[3] = f.w * scale; + } + } + else { + for (int i = 0; i < size; i++, in += pass_stride, pixels += 4) { + float4 f = make_float4(in[0], in[1], in[2], in[3]); + + pixels[0] = f.x * scale_exposure; + pixels[1] = f.y * scale_exposure; + pixels[2] = f.z * scale_exposure; + + /* clamp since alpha might be > 1.0 due to russian roulette */ + pixels[3] = saturate(f.w * scale); + } + } + } + + return true; + } + + return false; } /* Display Buffer */ DisplayBuffer::DisplayBuffer(Device *device, bool linear) -: draw_width(0), - draw_height(0), - transparent(true), /* todo: determine from background */ - half_float(linear), - rgba_byte(device, "display buffer byte"), - rgba_half(device, "display buffer half") + : draw_width(0), + draw_height(0), + transparent(true), /* todo: determine from background */ + half_float(linear), + rgba_byte(device, "display buffer byte"), + rgba_half(device, "display buffer half") { } DisplayBuffer::~DisplayBuffer() { - rgba_byte.free(); - rgba_half.free(); + rgba_byte.free(); + rgba_half.free(); } -void DisplayBuffer::reset(BufferParams& params_) +void DisplayBuffer::reset(BufferParams ¶ms_) { - draw_width = 0; - draw_height = 0; - - params = params_; - - /* allocate display pixels */ - if(half_float) { - rgba_half.alloc_to_device(params.width, params.height); - } - else { - rgba_byte.alloc_to_device(params.width, params.height); - } + draw_width = 0; + draw_height = 0; + + params = params_; + + /* allocate display pixels */ + if (half_float) { + rgba_half.alloc_to_device(params.width, params.height); + } + else { + rgba_byte.alloc_to_device(params.width, params.height); + } } void DisplayBuffer::draw_set(int width, int height) { - assert(width <= params.width && height <= params.height); + assert(width <= params.width && height <= params.height); - draw_width = width; - draw_height = height; + draw_width = width; + draw_height = height; } -void DisplayBuffer::draw(Device *device, const DeviceDrawParams& draw_params) +void DisplayBuffer::draw(Device *device, const DeviceDrawParams &draw_params) { - if(draw_width != 0 && draw_height != 0) { - device_memory& rgba = (half_float)? (device_memory&)rgba_half: - (device_memory&)rgba_byte; - - device->draw_pixels( - rgba, 0, - draw_width, draw_height, params.width, params.height, - params.full_x, params.full_y, params.full_width, params.full_height, - transparent, draw_params); - } + if (draw_width != 0 && draw_height != 0) { + device_memory &rgba = (half_float) ? (device_memory &)rgba_half : (device_memory &)rgba_byte; + + device->draw_pixels(rgba, + 0, + draw_width, + draw_height, + params.width, + params.height, + params.full_x, + params.full_y, + params.full_width, + params.full_height, + transparent, + draw_params); + } } bool DisplayBuffer::draw_ready() { - return (draw_width != 0 && draw_height != 0); + return (draw_width != 0 && draw_height != 0); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h index 0a010718d6d..1c49038cd4b 100644 --- a/intern/cycles/render/buffers.h +++ b/intern/cycles/render/buffers.h @@ -38,59 +38,65 @@ struct float4; * Size of render buffer and how it fits in the full image (border render). */ class BufferParams { -public: - /* width/height of the physical buffer */ - int width; - int height; - - /* offset into and width/height of the full buffer */ - int full_x; - int full_y; - int full_width; - int full_height; - - /* passes */ - vector<Pass> passes; - bool denoising_data_pass; - /* If only some light path types should be denoised, an additional pass is needed. */ - bool denoising_clean_pass; - /* When we're prefiltering the passes during rendering, we need to keep both the - * original and the prefiltered data around because neighboring tiles might still - * need the original data. */ - bool denoising_prefiltered_pass; - - /* functions */ - BufferParams(); - - void get_offset_stride(int& offset, int& stride); - bool modified(const BufferParams& params); - void add_pass(PassType type); - int get_passes_size(); - int get_denoising_offset(); - int get_denoising_prefiltered_offset(); + public: + /* width/height of the physical buffer */ + int width; + int height; + + /* offset into and width/height of the full buffer */ + int full_x; + int full_y; + int full_width; + int full_height; + + /* passes */ + vector<Pass> passes; + bool denoising_data_pass; + /* If only some light path types should be denoised, an additional pass is needed. */ + bool denoising_clean_pass; + /* When we're prefiltering the passes during rendering, we need to keep both the + * original and the prefiltered data around because neighboring tiles might still + * need the original data. */ + bool denoising_prefiltered_pass; + + /* functions */ + BufferParams(); + + void get_offset_stride(int &offset, int &stride); + bool modified(const BufferParams ¶ms); + void add_pass(PassType type); + int get_passes_size(); + int get_denoising_offset(); + int get_denoising_prefiltered_offset(); }; /* Render Buffers */ class RenderBuffers { -public: - /* buffer parameters */ - BufferParams params; - - /* float buffer */ - device_vector<float> buffer; - bool map_neighbor_copied; - double render_time; - - explicit RenderBuffers(Device *device); - ~RenderBuffers(); - - void reset(BufferParams& params); - void zero(); - - bool copy_from_device(); - bool get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels, const string &name); - bool get_denoising_pass_rect(int offset, float exposure, int sample, int components, float *pixels); + public: + /* buffer parameters */ + BufferParams params; + + /* float buffer */ + device_vector<float> buffer; + bool map_neighbor_copied; + double render_time; + + explicit RenderBuffers(Device *device); + ~RenderBuffers(); + + void reset(BufferParams ¶ms); + void zero(); + + bool copy_from_device(); + bool get_pass_rect(PassType type, + float exposure, + int sample, + int components, + float *pixels, + const string &name); + bool get_denoising_pass_rect( + int offset, float exposure, int sample, int components, float *pixels); }; /* Display Buffer @@ -99,56 +105,56 @@ public: * buffers to byte of half float storage */ class DisplayBuffer { -public: - /* buffer parameters */ - BufferParams params; - /* dimensions for how much of the buffer is actually ready for display. - * with progressive render we can be using only a subset of the buffer. - * if these are zero, it means nothing can be drawn yet */ - int draw_width, draw_height; - /* draw alpha channel? */ - bool transparent; - /* use half float? */ - bool half_float; - /* byte buffer for converted result */ - device_pixels<uchar4> rgba_byte; - device_pixels<half4> rgba_half; - - DisplayBuffer(Device *device, bool linear = false); - ~DisplayBuffer(); - - void reset(BufferParams& params); - - void draw_set(int width, int height); - void draw(Device *device, const DeviceDrawParams& draw_params); - bool draw_ready(); + public: + /* buffer parameters */ + BufferParams params; + /* dimensions for how much of the buffer is actually ready for display. + * with progressive render we can be using only a subset of the buffer. + * if these are zero, it means nothing can be drawn yet */ + int draw_width, draw_height; + /* draw alpha channel? */ + bool transparent; + /* use half float? */ + bool half_float; + /* byte buffer for converted result */ + device_pixels<uchar4> rgba_byte; + device_pixels<half4> rgba_half; + + DisplayBuffer(Device *device, bool linear = false); + ~DisplayBuffer(); + + void reset(BufferParams ¶ms); + + void draw_set(int width, int height); + void draw(Device *device, const DeviceDrawParams &draw_params); + bool draw_ready(); }; /* Render Tile * Rendering task on a buffer */ class RenderTile { -public: - typedef enum { PATH_TRACE, DENOISE } Task; + public: + typedef enum { PATH_TRACE, DENOISE } Task; - Task task; - int x, y, w, h; - int start_sample; - int num_samples; - int sample; - int resolution; - int offset; - int stride; - int tile_index; + Task task; + int x, y, w, h; + int start_sample; + int num_samples; + int sample; + int resolution; + int offset; + int stride; + int tile_index; - device_ptr buffer; - int device_size; + device_ptr buffer; + int device_size; - RenderBuffers *buffers; + RenderBuffers *buffers; - RenderTile(); + RenderTile(); }; CCL_NAMESPACE_END -#endif /* __BUFFERS_H__ */ +#endif /* __BUFFERS_H__ */ diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 82aeb324a00..9c9070c8a90 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -39,147 +39,148 @@ CCL_NAMESPACE_BEGIN -static float shutter_curve_eval(float x, - array<float>& shutter_curve) +static float shutter_curve_eval(float x, array<float> &shutter_curve) { - if(shutter_curve.size() == 0) { - return 1.0f; - } - - x *= shutter_curve.size(); - int index = (int)x; - float frac = x - index; - if(index < shutter_curve.size() - 1) { - return lerp(shutter_curve[index], shutter_curve[index + 1], frac); - } - else { - return shutter_curve[shutter_curve.size() - 1]; - } + if (shutter_curve.size() == 0) { + return 1.0f; + } + + x *= shutter_curve.size(); + int index = (int)x; + float frac = x - index; + if (index < shutter_curve.size() - 1) { + return lerp(shutter_curve[index], shutter_curve[index + 1], frac); + } + else { + return shutter_curve[shutter_curve.size() - 1]; + } } NODE_DEFINE(Camera) { - NodeType* type = NodeType::add("camera", create); - - SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f); - - static NodeEnum motion_position_enum; - motion_position_enum.insert("start", MOTION_POSITION_START); - motion_position_enum.insert("center", MOTION_POSITION_CENTER); - motion_position_enum.insert("end", MOTION_POSITION_END); - SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER); - - static NodeEnum rolling_shutter_type_enum; - rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE); - rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP); - SOCKET_ENUM(rolling_shutter_type, "Rolling Shutter Type", rolling_shutter_type_enum, ROLLING_SHUTTER_NONE); - SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f); - - SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>()); - - SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f); - SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f); - SOCKET_UINT(blades, "Blades", 0); - SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f); - - SOCKET_TRANSFORM(matrix, "Matrix", transform_identity()); - SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>()); - - SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f); - - static NodeEnum type_enum; - type_enum.insert("perspective", CAMERA_PERSPECTIVE); - type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC); - type_enum.insert("panorama", CAMERA_PANORAMA); - SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE); - - static NodeEnum panorama_type_enum; - panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR); - panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL); - panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT); - panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID); - SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR); - - SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F); - SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f); - SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F); - SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F); - SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F); - SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F); - SOCKET_FLOAT(fov, "FOV", M_PI_4_F); - SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F); - SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F); - - static NodeEnum stereo_eye_enum; - stereo_eye_enum.insert("none", STEREO_NONE); - stereo_eye_enum.insert("left", STEREO_LEFT); - stereo_eye_enum.insert("right", STEREO_RIGHT); - SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE); - - SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f); - SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f); - - SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false); - SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f); - SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f); - - SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f); - SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f); - - SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f); - SOCKET_FLOAT(farclip, "Far Clip", 1e5f); - - SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0); - SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0); - SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0); - SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0); - - SOCKET_FLOAT(border.left, "Border Left", 0); - SOCKET_FLOAT(border.right, "Border Right", 0); - SOCKET_FLOAT(border.bottom, "Border Bottom", 0); - SOCKET_FLOAT(border.top, "Border Top", 0); - - SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f); - - return type; + NodeType *type = NodeType::add("camera", create); + + SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f); + + static NodeEnum motion_position_enum; + motion_position_enum.insert("start", MOTION_POSITION_START); + motion_position_enum.insert("center", MOTION_POSITION_CENTER); + motion_position_enum.insert("end", MOTION_POSITION_END); + SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER); + + static NodeEnum rolling_shutter_type_enum; + rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE); + rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP); + SOCKET_ENUM(rolling_shutter_type, + "Rolling Shutter Type", + rolling_shutter_type_enum, + ROLLING_SHUTTER_NONE); + SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f); + + SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>()); + + SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f); + SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f); + SOCKET_UINT(blades, "Blades", 0); + SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f); + + SOCKET_TRANSFORM(matrix, "Matrix", transform_identity()); + SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>()); + + SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f); + + static NodeEnum type_enum; + type_enum.insert("perspective", CAMERA_PERSPECTIVE); + type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC); + type_enum.insert("panorama", CAMERA_PANORAMA); + SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE); + + static NodeEnum panorama_type_enum; + panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR); + panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL); + panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT); + panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID); + SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR); + + SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F); + SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f); + SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F); + SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F); + SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F); + SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F); + SOCKET_FLOAT(fov, "FOV", M_PI_4_F); + SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F); + SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F); + + static NodeEnum stereo_eye_enum; + stereo_eye_enum.insert("none", STEREO_NONE); + stereo_eye_enum.insert("left", STEREO_LEFT); + stereo_eye_enum.insert("right", STEREO_RIGHT); + SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE); + + SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f); + SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f); + + SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false); + SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f); + SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f); + + SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f); + SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f); + + SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f); + SOCKET_FLOAT(farclip, "Far Clip", 1e5f); + + SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0); + SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0); + SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0); + SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0); + + SOCKET_FLOAT(border.left, "Border Left", 0); + SOCKET_FLOAT(border.right, "Border Right", 0); + SOCKET_FLOAT(border.bottom, "Border Bottom", 0); + SOCKET_FLOAT(border.top, "Border Top", 0); + + SOCKET_FLOAT(offscreen_dicing_scale, "Offscreen Dicing Scale", 1.0f); + + return type; } -Camera::Camera() -: Node(node_type) +Camera::Camera() : Node(node_type) { - shutter_table_offset = TABLE_OFFSET_INVALID; + shutter_table_offset = TABLE_OFFSET_INVALID; - width = 1024; - height = 512; - resolution = 1; + width = 1024; + height = 512; + resolution = 1; - use_perspective_motion = false; + use_perspective_motion = false; - shutter_curve.resize(RAMP_TABLE_SIZE); - for(int i = 0; i < shutter_curve.size(); ++i) { - shutter_curve[i] = 1.0f; - } + shutter_curve.resize(RAMP_TABLE_SIZE); + for (int i = 0; i < shutter_curve.size(); ++i) { + shutter_curve[i] = 1.0f; + } - compute_auto_viewplane(); + compute_auto_viewplane(); - screentoworld = projection_identity(); - rastertoworld = projection_identity(); - ndctoworld = projection_identity(); - rastertocamera = projection_identity(); - cameratoworld = transform_identity(); - worldtoraster = projection_identity(); + screentoworld = projection_identity(); + rastertoworld = projection_identity(); + ndctoworld = projection_identity(); + rastertocamera = projection_identity(); + cameratoworld = transform_identity(); + worldtoraster = projection_identity(); - full_rastertocamera = projection_identity(); + full_rastertocamera = projection_identity(); - dx = make_float3(0.0f, 0.0f, 0.0f); - dy = make_float3(0.0f, 0.0f, 0.0f); + dx = make_float3(0.0f, 0.0f, 0.0f); + dy = make_float3(0.0f, 0.0f, 0.0f); - need_update = true; - need_device_update = true; - need_flags_update = true; - previous_need_motion = -1; + need_update = true; + need_device_update = true; + need_flags_update = true; + previous_need_motion = -1; - memset((void *)&kernel_camera, 0, sizeof(kernel_camera)); + memset((void *)&kernel_camera, 0, sizeof(kernel_camera)); } Camera::~Camera() @@ -188,589 +189,577 @@ Camera::~Camera() void Camera::compute_auto_viewplane() { - if(type == CAMERA_PANORAMA) { - viewplane.left = 0.0f; - viewplane.right = 1.0f; - viewplane.bottom = 0.0f; - viewplane.top = 1.0f; - } - else { - float aspect = (float)width/(float)height; - if(width >= height) { - viewplane.left = -aspect; - viewplane.right = aspect; - viewplane.bottom = -1.0f; - viewplane.top = 1.0f; - } - else { - viewplane.left = -1.0f; - viewplane.right = 1.0f; - viewplane.bottom = -1.0f/aspect; - viewplane.top = 1.0f/aspect; - } - } + if (type == CAMERA_PANORAMA) { + viewplane.left = 0.0f; + viewplane.right = 1.0f; + viewplane.bottom = 0.0f; + viewplane.top = 1.0f; + } + else { + float aspect = (float)width / (float)height; + if (width >= height) { + viewplane.left = -aspect; + viewplane.right = aspect; + viewplane.bottom = -1.0f; + viewplane.top = 1.0f; + } + else { + viewplane.left = -1.0f; + viewplane.right = 1.0f; + viewplane.bottom = -1.0f / aspect; + viewplane.top = 1.0f / aspect; + } + } } void Camera::update(Scene *scene) { - Scene::MotionType need_motion = scene->need_motion(); - - if(previous_need_motion != need_motion) { - /* scene's motion model could have been changed since previous device - * camera update this could happen for example in case when one render - * layer has got motion pass and another not */ - need_device_update = true; - } - - if(!need_update) - return; - - /* Full viewport to camera border in the viewport. */ - Transform fulltoborder = transform_from_viewplane(viewport_camera_border); - Transform bordertofull = transform_inverse(fulltoborder); - - /* ndc to raster */ - Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull; - Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull; - - /* raster to screen */ - Transform screentondc = fulltoborder * transform_from_viewplane(viewplane); - - Transform screentoraster = ndctoraster * screentondc; - Transform rastertoscreen = transform_inverse(screentoraster); - Transform full_screentoraster = full_ndctoraster * screentondc; - Transform full_rastertoscreen = transform_inverse(full_screentoraster); - - /* screen to camera */ - ProjectionTransform cameratoscreen; - if(type == CAMERA_PERSPECTIVE) - cameratoscreen = projection_perspective(fov, nearclip, farclip); - else if(type == CAMERA_ORTHOGRAPHIC) - cameratoscreen = projection_orthographic(nearclip, farclip); - else - cameratoscreen = projection_identity(); - - ProjectionTransform screentocamera = projection_inverse(cameratoscreen); - - rastertocamera = screentocamera * rastertoscreen; - full_rastertocamera = screentocamera * full_rastertoscreen; - cameratoraster = screentoraster * cameratoscreen; - - cameratoworld = matrix; - screentoworld = cameratoworld * screentocamera; - rastertoworld = cameratoworld * rastertocamera; - ndctoworld = rastertoworld * ndctoraster; - - /* note we recompose matrices instead of taking inverses of the above, this - * is needed to avoid inverting near degenerate matrices that happen due to - * precision issues with large scenes */ - worldtocamera = transform_inverse(matrix); - worldtoscreen = cameratoscreen * worldtocamera; - worldtondc = screentondc * worldtoscreen; - worldtoraster = ndctoraster * worldtondc; - - /* differentials */ - if(type == CAMERA_ORTHOGRAPHIC) { - dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0)); - dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0)); - full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0)); - full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0)); - } - else if(type == CAMERA_PERSPECTIVE) { - dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) - - transform_perspective(&rastertocamera, make_float3(0, 0, 0)); - dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) - - transform_perspective(&rastertocamera, make_float3(0, 0, 0)); - full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) - - transform_perspective(&full_rastertocamera, make_float3(0, 0, 0)); - full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) - - transform_perspective(&full_rastertocamera, make_float3(0, 0, 0)); - } - else { - dx = make_float3(0.0f, 0.0f, 0.0f); - dy = make_float3(0.0f, 0.0f, 0.0f); - } - - dx = transform_direction(&cameratoworld, dx); - dy = transform_direction(&cameratoworld, dy); - full_dx = transform_direction(&cameratoworld, full_dx); - full_dy = transform_direction(&cameratoworld, full_dy); - - if(type == CAMERA_PERSPECTIVE) { - float3 v = transform_perspective(&full_rastertocamera, make_float3(full_width, full_height, 1.0f)); - - frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x)); - frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y)); - } - - /* Compute kernel camera data. */ - KernelCamera *kcam = &kernel_camera; - - /* store matrices */ - kcam->screentoworld = screentoworld; - kcam->rastertoworld = rastertoworld; - kcam->rastertocamera = rastertocamera; - kcam->cameratoworld = cameratoworld; - kcam->worldtocamera = worldtocamera; - kcam->worldtoscreen = worldtoscreen; - kcam->worldtoraster = worldtoraster; - kcam->worldtondc = worldtondc; - kcam->ndctoworld = ndctoworld; - - /* camera motion */ - kcam->num_motion_steps = 0; - kcam->have_perspective_motion = 0; - kernel_camera_motion.clear(); - - /* Test if any of the transforms are actually different. */ - bool have_motion = false; - for(size_t i = 0; i < motion.size(); i++) { - have_motion = have_motion || motion[i] != matrix; - } - - if(need_motion == Scene::MOTION_PASS) { - /* TODO(sergey): Support perspective (zoom, fov) motion. */ - if(type == CAMERA_PANORAMA) { - if(have_motion) { - kcam->motion_pass_pre = transform_inverse(motion[0]); - kcam->motion_pass_post = transform_inverse(motion[motion.size()-1]); - } - else { - kcam->motion_pass_pre = kcam->worldtocamera; - kcam->motion_pass_post = kcam->worldtocamera; - } - } - else { - if(have_motion) { - kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]); - kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size()-1]); - } - else { - kcam->perspective_pre = worldtoraster; - kcam->perspective_post = worldtoraster; - } - } - } - else if(need_motion == Scene::MOTION_BLUR) { - if(have_motion) { - kernel_camera_motion.resize(motion.size()); - transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size()); - kcam->num_motion_steps = motion.size(); - } - - /* TODO(sergey): Support other types of camera. */ - if(use_perspective_motion && type == CAMERA_PERSPECTIVE) { - /* TODO(sergey): Move to an utility function and de-duplicate with - * calculation above. - */ - ProjectionTransform screentocamera_pre = - projection_inverse(projection_perspective(fov_pre, - nearclip, - farclip)); - ProjectionTransform screentocamera_post = - projection_inverse(projection_perspective(fov_post, - nearclip, - farclip)); - - kcam->perspective_pre = screentocamera_pre * rastertoscreen; - kcam->perspective_post = screentocamera_post * rastertoscreen; - kcam->have_perspective_motion = 1; - } - } - - /* depth of field */ - kcam->aperturesize = aperturesize; - kcam->focaldistance = focaldistance; - kcam->blades = (blades < 3)? 0.0f: blades; - kcam->bladesrotation = bladesrotation; - - /* motion blur */ - kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: -1.0f; - - /* type */ - kcam->type = type; - - /* anamorphic lens bokeh */ - kcam->inv_aperture_ratio = 1.0f / aperture_ratio; - - /* panorama */ - kcam->panorama_type = panorama_type; - kcam->fisheye_fov = fisheye_fov; - kcam->fisheye_lens = fisheye_lens; - kcam->equirectangular_range = make_float4(longitude_min - longitude_max, -longitude_min, - latitude_min - latitude_max, -latitude_min + M_PI_2_F); - - switch(stereo_eye) { - case STEREO_LEFT: - kcam->interocular_offset = -interocular_distance * 0.5f; - break; - case STEREO_RIGHT: - kcam->interocular_offset = interocular_distance * 0.5f; - break; - case STEREO_NONE: - default: - kcam->interocular_offset = 0.0f; - break; - } - - kcam->convergence_distance = convergence_distance; - if(use_pole_merge) { - kcam->pole_merge_angle_from = pole_merge_angle_from; - kcam->pole_merge_angle_to = pole_merge_angle_to; - } - else { - kcam->pole_merge_angle_from = -1.0f; - kcam->pole_merge_angle_to = -1.0f; - } - - /* sensor size */ - kcam->sensorwidth = sensorwidth; - kcam->sensorheight = sensorheight; - - /* render size */ - kcam->width = width; - kcam->height = height; - kcam->resolution = resolution; - - /* store differentials */ - kcam->dx = float3_to_float4(dx); - kcam->dy = float3_to_float4(dy); - - /* clipping */ - kcam->nearclip = nearclip; - kcam->cliplength = (farclip == FLT_MAX)? FLT_MAX: farclip - nearclip; - - /* Camera in volume. */ - kcam->is_inside_volume = 0; - - /* Rolling shutter effect */ - kcam->rolling_shutter_type = rolling_shutter_type; - kcam->rolling_shutter_duration = rolling_shutter_duration; - - /* Set further update flags */ - need_update = false; - need_device_update = true; - need_flags_update = true; - previous_need_motion = need_motion; + Scene::MotionType need_motion = scene->need_motion(); + + if (previous_need_motion != need_motion) { + /* scene's motion model could have been changed since previous device + * camera update this could happen for example in case when one render + * layer has got motion pass and another not */ + need_device_update = true; + } + + if (!need_update) + return; + + /* Full viewport to camera border in the viewport. */ + Transform fulltoborder = transform_from_viewplane(viewport_camera_border); + Transform bordertofull = transform_inverse(fulltoborder); + + /* ndc to raster */ + Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull; + Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull; + + /* raster to screen */ + Transform screentondc = fulltoborder * transform_from_viewplane(viewplane); + + Transform screentoraster = ndctoraster * screentondc; + Transform rastertoscreen = transform_inverse(screentoraster); + Transform full_screentoraster = full_ndctoraster * screentondc; + Transform full_rastertoscreen = transform_inverse(full_screentoraster); + + /* screen to camera */ + ProjectionTransform cameratoscreen; + if (type == CAMERA_PERSPECTIVE) + cameratoscreen = projection_perspective(fov, nearclip, farclip); + else if (type == CAMERA_ORTHOGRAPHIC) + cameratoscreen = projection_orthographic(nearclip, farclip); + else + cameratoscreen = projection_identity(); + + ProjectionTransform screentocamera = projection_inverse(cameratoscreen); + + rastertocamera = screentocamera * rastertoscreen; + full_rastertocamera = screentocamera * full_rastertoscreen; + cameratoraster = screentoraster * cameratoscreen; + + cameratoworld = matrix; + screentoworld = cameratoworld * screentocamera; + rastertoworld = cameratoworld * rastertocamera; + ndctoworld = rastertoworld * ndctoraster; + + /* note we recompose matrices instead of taking inverses of the above, this + * is needed to avoid inverting near degenerate matrices that happen due to + * precision issues with large scenes */ + worldtocamera = transform_inverse(matrix); + worldtoscreen = cameratoscreen * worldtocamera; + worldtondc = screentondc * worldtoscreen; + worldtoraster = ndctoraster * worldtondc; + + /* differentials */ + if (type == CAMERA_ORTHOGRAPHIC) { + dx = transform_perspective_direction(&rastertocamera, make_float3(1, 0, 0)); + dy = transform_perspective_direction(&rastertocamera, make_float3(0, 1, 0)); + full_dx = transform_perspective_direction(&full_rastertocamera, make_float3(1, 0, 0)); + full_dy = transform_perspective_direction(&full_rastertocamera, make_float3(0, 1, 0)); + } + else if (type == CAMERA_PERSPECTIVE) { + dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) - + transform_perspective(&rastertocamera, make_float3(0, 0, 0)); + dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) - + transform_perspective(&rastertocamera, make_float3(0, 0, 0)); + full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) - + transform_perspective(&full_rastertocamera, make_float3(0, 0, 0)); + full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) - + transform_perspective(&full_rastertocamera, make_float3(0, 0, 0)); + } + else { + dx = make_float3(0.0f, 0.0f, 0.0f); + dy = make_float3(0.0f, 0.0f, 0.0f); + } + + dx = transform_direction(&cameratoworld, dx); + dy = transform_direction(&cameratoworld, dy); + full_dx = transform_direction(&cameratoworld, full_dx); + full_dy = transform_direction(&cameratoworld, full_dy); + + if (type == CAMERA_PERSPECTIVE) { + float3 v = transform_perspective(&full_rastertocamera, + make_float3(full_width, full_height, 1.0f)); + + frustum_right_normal = normalize(make_float3(v.z, 0.0f, -v.x)); + frustum_top_normal = normalize(make_float3(0.0f, v.z, -v.y)); + } + + /* Compute kernel camera data. */ + KernelCamera *kcam = &kernel_camera; + + /* store matrices */ + kcam->screentoworld = screentoworld; + kcam->rastertoworld = rastertoworld; + kcam->rastertocamera = rastertocamera; + kcam->cameratoworld = cameratoworld; + kcam->worldtocamera = worldtocamera; + kcam->worldtoscreen = worldtoscreen; + kcam->worldtoraster = worldtoraster; + kcam->worldtondc = worldtondc; + kcam->ndctoworld = ndctoworld; + + /* camera motion */ + kcam->num_motion_steps = 0; + kcam->have_perspective_motion = 0; + kernel_camera_motion.clear(); + + /* Test if any of the transforms are actually different. */ + bool have_motion = false; + for (size_t i = 0; i < motion.size(); i++) { + have_motion = have_motion || motion[i] != matrix; + } + + if (need_motion == Scene::MOTION_PASS) { + /* TODO(sergey): Support perspective (zoom, fov) motion. */ + if (type == CAMERA_PANORAMA) { + if (have_motion) { + kcam->motion_pass_pre = transform_inverse(motion[0]); + kcam->motion_pass_post = transform_inverse(motion[motion.size() - 1]); + } + else { + kcam->motion_pass_pre = kcam->worldtocamera; + kcam->motion_pass_post = kcam->worldtocamera; + } + } + else { + if (have_motion) { + kcam->perspective_pre = cameratoraster * transform_inverse(motion[0]); + kcam->perspective_post = cameratoraster * transform_inverse(motion[motion.size() - 1]); + } + else { + kcam->perspective_pre = worldtoraster; + kcam->perspective_post = worldtoraster; + } + } + } + else if (need_motion == Scene::MOTION_BLUR) { + if (have_motion) { + kernel_camera_motion.resize(motion.size()); + transform_motion_decompose(kernel_camera_motion.data(), motion.data(), motion.size()); + kcam->num_motion_steps = motion.size(); + } + + /* TODO(sergey): Support other types of camera. */ + if (use_perspective_motion && type == CAMERA_PERSPECTIVE) { + /* TODO(sergey): Move to an utility function and de-duplicate with + * calculation above. + */ + ProjectionTransform screentocamera_pre = projection_inverse( + projection_perspective(fov_pre, nearclip, farclip)); + ProjectionTransform screentocamera_post = projection_inverse( + projection_perspective(fov_post, nearclip, farclip)); + + kcam->perspective_pre = screentocamera_pre * rastertoscreen; + kcam->perspective_post = screentocamera_post * rastertoscreen; + kcam->have_perspective_motion = 1; + } + } + + /* depth of field */ + kcam->aperturesize = aperturesize; + kcam->focaldistance = focaldistance; + kcam->blades = (blades < 3) ? 0.0f : blades; + kcam->bladesrotation = bladesrotation; + + /* motion blur */ + kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f; + + /* type */ + kcam->type = type; + + /* anamorphic lens bokeh */ + kcam->inv_aperture_ratio = 1.0f / aperture_ratio; + + /* panorama */ + kcam->panorama_type = panorama_type; + kcam->fisheye_fov = fisheye_fov; + kcam->fisheye_lens = fisheye_lens; + kcam->equirectangular_range = make_float4(longitude_min - longitude_max, + -longitude_min, + latitude_min - latitude_max, + -latitude_min + M_PI_2_F); + + switch (stereo_eye) { + case STEREO_LEFT: + kcam->interocular_offset = -interocular_distance * 0.5f; + break; + case STEREO_RIGHT: + kcam->interocular_offset = interocular_distance * 0.5f; + break; + case STEREO_NONE: + default: + kcam->interocular_offset = 0.0f; + break; + } + + kcam->convergence_distance = convergence_distance; + if (use_pole_merge) { + kcam->pole_merge_angle_from = pole_merge_angle_from; + kcam->pole_merge_angle_to = pole_merge_angle_to; + } + else { + kcam->pole_merge_angle_from = -1.0f; + kcam->pole_merge_angle_to = -1.0f; + } + + /* sensor size */ + kcam->sensorwidth = sensorwidth; + kcam->sensorheight = sensorheight; + + /* render size */ + kcam->width = width; + kcam->height = height; + kcam->resolution = resolution; + + /* store differentials */ + kcam->dx = float3_to_float4(dx); + kcam->dy = float3_to_float4(dy); + + /* clipping */ + kcam->nearclip = nearclip; + kcam->cliplength = (farclip == FLT_MAX) ? FLT_MAX : farclip - nearclip; + + /* Camera in volume. */ + kcam->is_inside_volume = 0; + + /* Rolling shutter effect */ + kcam->rolling_shutter_type = rolling_shutter_type; + kcam->rolling_shutter_duration = rolling_shutter_duration; + + /* Set further update flags */ + need_update = false; + need_device_update = true; + need_flags_update = true; + previous_need_motion = need_motion; } -void Camera::device_update(Device * /* device */, - DeviceScene *dscene, - Scene *scene) +void Camera::device_update(Device * /* device */, DeviceScene *dscene, Scene *scene) { - update(scene); - - if(!need_device_update) - return; - - scene->lookup_tables->remove_table(&shutter_table_offset); - if(kernel_camera.shuttertime != -1.0f) { - vector<float> shutter_table; - util_cdf_inverted(SHUTTER_TABLE_SIZE, - 0.0f, - 1.0f, - function_bind(shutter_curve_eval, _1, shutter_curve), - false, - shutter_table); - shutter_table_offset = scene->lookup_tables->add_table(dscene, - shutter_table); - kernel_camera.shutter_table_offset = (int)shutter_table_offset; - } - - dscene->data.cam = kernel_camera; - - size_t num_motion_steps = kernel_camera_motion.size(); - if(num_motion_steps) { - DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps); - memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps); - dscene->camera_motion.copy_to_device(); - } - else { - dscene->camera_motion.free(); - } + update(scene); + + if (!need_device_update) + return; + + scene->lookup_tables->remove_table(&shutter_table_offset); + if (kernel_camera.shuttertime != -1.0f) { + vector<float> shutter_table; + util_cdf_inverted(SHUTTER_TABLE_SIZE, + 0.0f, + 1.0f, + function_bind(shutter_curve_eval, _1, shutter_curve), + false, + shutter_table); + shutter_table_offset = scene->lookup_tables->add_table(dscene, shutter_table); + kernel_camera.shutter_table_offset = (int)shutter_table_offset; + } + + dscene->data.cam = kernel_camera; + + size_t num_motion_steps = kernel_camera_motion.size(); + if (num_motion_steps) { + DecomposedTransform *camera_motion = dscene->camera_motion.alloc(num_motion_steps); + memcpy(camera_motion, kernel_camera_motion.data(), sizeof(*camera_motion) * num_motion_steps); + dscene->camera_motion.copy_to_device(); + } + else { + dscene->camera_motion.free(); + } } -void Camera::device_update_volume(Device * /*device*/, - DeviceScene *dscene, - Scene *scene) +void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scene *scene) { - if(!need_device_update && !need_flags_update) { - return; - } - KernelCamera *kcam = &dscene->data.cam; - BoundBox viewplane_boundbox = viewplane_bounds_get(); - for(size_t i = 0; i < scene->objects.size(); ++i) { - Object *object = scene->objects[i]; - if(object->mesh->has_volume && - viewplane_boundbox.intersects(object->bounds)) - { - /* TODO(sergey): Consider adding more grained check. */ - VLOG(1) << "Detected camera inside volume."; - kcam->is_inside_volume = 1; - break; - } - } - if(!kcam->is_inside_volume) { - VLOG(1) << "Camera is outside of the volume."; - } - need_device_update = false; - need_flags_update = false; + if (!need_device_update && !need_flags_update) { + return; + } + KernelCamera *kcam = &dscene->data.cam; + BoundBox viewplane_boundbox = viewplane_bounds_get(); + for (size_t i = 0; i < scene->objects.size(); ++i) { + Object *object = scene->objects[i]; + if (object->mesh->has_volume && viewplane_boundbox.intersects(object->bounds)) { + /* TODO(sergey): Consider adding more grained check. */ + VLOG(1) << "Detected camera inside volume."; + kcam->is_inside_volume = 1; + break; + } + } + if (!kcam->is_inside_volume) { + VLOG(1) << "Camera is outside of the volume."; + } + need_device_update = false; + need_flags_update = false; } -void Camera::device_free(Device * /*device*/, - DeviceScene *dscene, - Scene *scene) +void Camera::device_free(Device * /*device*/, DeviceScene *dscene, Scene *scene) { - scene->lookup_tables->remove_table(&shutter_table_offset); - dscene->camera_motion.free(); + scene->lookup_tables->remove_table(&shutter_table_offset); + dscene->camera_motion.free(); } -bool Camera::modified(const Camera& cam) +bool Camera::modified(const Camera &cam) { - return !Node::equals(cam); + return !Node::equals(cam); } -bool Camera::motion_modified(const Camera& cam) +bool Camera::motion_modified(const Camera &cam) { - return !((motion == cam.motion) && - (use_perspective_motion == cam.use_perspective_motion)); + return !((motion == cam.motion) && (use_perspective_motion == cam.use_perspective_motion)); } void Camera::tag_update() { - need_update = true; + need_update = true; } float3 Camera::transform_raster_to_world(float raster_x, float raster_y) { - float3 D, P; - if(type == CAMERA_PERSPECTIVE) { - D = transform_perspective(&rastertocamera, - make_float3(raster_x, raster_y, 0.0f)); - float3 Pclip = normalize(D); - P = make_float3(0.0f, 0.0f, 0.0f); - /* TODO(sergey): Aperture support? */ - P = transform_point(&cameratoworld, P); - D = normalize(transform_direction(&cameratoworld, D)); - /* TODO(sergey): Clipping is conditional in kernel, and hence it could - * be mistakes in here, currently leading to wrong camera-in-volume - * detection. - */ - P += nearclip * D / Pclip.z; - } - else if(type == CAMERA_ORTHOGRAPHIC) { - D = make_float3(0.0f, 0.0f, 1.0f); - /* TODO(sergey): Aperture support? */ - P = transform_perspective(&rastertocamera, - make_float3(raster_x, raster_y, 0.0f)); - P = transform_point(&cameratoworld, P); - D = normalize(transform_direction(&cameratoworld, D)); - } - else { - assert(!"unsupported camera type"); - } - return P; + float3 D, P; + if (type == CAMERA_PERSPECTIVE) { + D = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + float3 Pclip = normalize(D); + P = make_float3(0.0f, 0.0f, 0.0f); + /* TODO(sergey): Aperture support? */ + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); + /* TODO(sergey): Clipping is conditional in kernel, and hence it could + * be mistakes in here, currently leading to wrong camera-in-volume + * detection. + */ + P += nearclip * D / Pclip.z; + } + else if (type == CAMERA_ORTHOGRAPHIC) { + D = make_float3(0.0f, 0.0f, 1.0f); + /* TODO(sergey): Aperture support? */ + P = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); + } + else { + assert(!"unsupported camera type"); + } + return P; } BoundBox Camera::viewplane_bounds_get() { - /* TODO(sergey): This is all rather stupid, but is there a way to perform - * checks we need in a more clear and smart fasion? - */ - BoundBox bounds = BoundBox::empty; - - if(type == CAMERA_PANORAMA) { - if(use_spherical_stereo == false) { - bounds.grow(make_float3(cameratoworld.x.w, - cameratoworld.y.w, - cameratoworld.z.w)); - } - else { - float half_eye_distance = interocular_distance * 0.5f; - - bounds.grow(make_float3(cameratoworld.x.w + half_eye_distance, - cameratoworld.y.w, - cameratoworld.z.w)); - - bounds.grow(make_float3(cameratoworld.z.w, - cameratoworld.y.w + half_eye_distance, - cameratoworld.z.w)); - - bounds.grow(make_float3(cameratoworld.x.w - half_eye_distance, - cameratoworld.y.w, - cameratoworld.z.w)); - - bounds.grow(make_float3(cameratoworld.x.w, - cameratoworld.y.w - half_eye_distance, - cameratoworld.z.w)); - } - } - else { - bounds.grow(transform_raster_to_world(0.0f, 0.0f)); - bounds.grow(transform_raster_to_world(0.0f, (float)height)); - bounds.grow(transform_raster_to_world((float)width, (float)height)); - bounds.grow(transform_raster_to_world((float)width, 0.0f)); - if(type == CAMERA_PERSPECTIVE) { - /* Center point has the most distance in local Z axis, - * use it to construct bounding box/ - */ - bounds.grow(transform_raster_to_world(0.5f*width, 0.5f*height)); - } - } - return bounds; + /* TODO(sergey): This is all rather stupid, but is there a way to perform + * checks we need in a more clear and smart fasion? + */ + BoundBox bounds = BoundBox::empty; + + if (type == CAMERA_PANORAMA) { + if (use_spherical_stereo == false) { + bounds.grow(make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w)); + } + else { + float half_eye_distance = interocular_distance * 0.5f; + + bounds.grow(make_float3( + cameratoworld.x.w + half_eye_distance, cameratoworld.y.w, cameratoworld.z.w)); + + bounds.grow(make_float3( + cameratoworld.z.w, cameratoworld.y.w + half_eye_distance, cameratoworld.z.w)); + + bounds.grow(make_float3( + cameratoworld.x.w - half_eye_distance, cameratoworld.y.w, cameratoworld.z.w)); + + bounds.grow(make_float3( + cameratoworld.x.w, cameratoworld.y.w - half_eye_distance, cameratoworld.z.w)); + } + } + else { + bounds.grow(transform_raster_to_world(0.0f, 0.0f)); + bounds.grow(transform_raster_to_world(0.0f, (float)height)); + bounds.grow(transform_raster_to_world((float)width, (float)height)); + bounds.grow(transform_raster_to_world((float)width, 0.0f)); + if (type == CAMERA_PERSPECTIVE) { + /* Center point has the most distance in local Z axis, + * use it to construct bounding box/ + */ + bounds.grow(transform_raster_to_world(0.5f * width, 0.5f * height)); + } + } + return bounds; } float Camera::world_to_raster_size(float3 P) { - float res = 1.0f; - - if(type == CAMERA_ORTHOGRAPHIC) { - res = min(len(full_dx), len(full_dy)); - - if(offscreen_dicing_scale > 1.0f) { - float3 p = transform_point(&worldtocamera, P); - float3 v = transform_perspective(&full_rastertocamera, make_float3(full_width, full_height, 0.0f)); - - /* Create point clamped to frustum */ - float3 c; - c.x = max(-v.x, min(v.x, p.x)); - c.y = max(-v.y, min(v.y, p.y)); - c.z = max(0.0f, p.z); - - float f_dist = len(p - c) / sqrtf((v.x*v.x+v.y*v.y)*0.5f); - - if(f_dist > 0.0f) { - res += res * f_dist * (offscreen_dicing_scale - 1.0f); - } - } - } - else if(type == CAMERA_PERSPECTIVE) { - /* Calculate as if point is directly ahead of the camera. */ - float3 raster = make_float3(0.5f*full_width, 0.5f*full_height, 0.0f); - float3 Pcamera = transform_perspective(&full_rastertocamera, raster); - - /* dDdx */ - float3 Ddiff = transform_direction(&cameratoworld, Pcamera); - float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy; - float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff); - - /* dPdx */ - float dist = len(transform_point(&worldtocamera, P)); - float3 D = normalize(Ddiff); - res = len(dist*dDdx - dot(dist*dDdx, D)*D); - - /* Decent approx distance to frustum (doesn't handle corners correctly, but not that big of a deal) */ - float f_dist = 0.0f; - - if(offscreen_dicing_scale > 1.0f) { - float3 p = transform_point(&worldtocamera, P); - - /* Distance from the four planes */ - float r = dot(p, frustum_right_normal); - float t = dot(p, frustum_top_normal); - p = make_float3(-p.x, -p.y, p.z); - float l = dot(p, frustum_right_normal); - float b = dot(p, frustum_top_normal); - p = make_float3(-p.x, -p.y, p.z); - - if(r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) { - /* Point is inside frustum */ - f_dist = 0.0f; - } - else if(r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) { - /* Point is behind frustum */ - f_dist = len(p); - } - else { - /* Point may be behind or off to the side, need to check */ - float3 along_right = make_float3(-frustum_right_normal.z, 0.0f, frustum_right_normal.x); - float3 along_left = make_float3(frustum_right_normal.z, 0.0f, frustum_right_normal.x); - float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y); - float3 along_bottom = make_float3(0.0f, frustum_top_normal.z, frustum_top_normal.y); - - float dist[] = {r, l, t, b}; - float3 along[] = {along_right, along_left, along_top, along_bottom}; - - bool test_o = false; - - float *d = dist; - float3 *a = along; - for(int i = 0; i < 4; i++, d++, a++) { - /* Test if we should check this side at all */ - if(*d > 0.0f) { - if(dot(p, *a) >= 0.0f) { - /* We are in front of the back edge of this side of the frustum */ - f_dist = max(f_dist, *d); - } - else { - /* Possibly far enough behind the frustum to use distance to origin instead of edge */ - test_o = true; - } - } - } - - if(test_o) { - f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p); - } - } - - if(f_dist > 0.0f) { - res += len(dDdx - dot(dDdx, D)*D) * f_dist * (offscreen_dicing_scale - 1.0f); - } - } - } - else if(type == CAMERA_PANORAMA) { - float3 D = transform_point(&worldtocamera, P); - float dist = len(D); - - Ray ray = {{0}}; - - /* Distortion can become so great that the results become meaningless, there - * may be a better way to do this, but calculating differentials from the - * point directly ahead seems to produce good enough results. */ + float res = 1.0f; + + if (type == CAMERA_ORTHOGRAPHIC) { + res = min(len(full_dx), len(full_dy)); + + if (offscreen_dicing_scale > 1.0f) { + float3 p = transform_point(&worldtocamera, P); + float3 v = transform_perspective(&full_rastertocamera, + make_float3(full_width, full_height, 0.0f)); + + /* Create point clamped to frustum */ + float3 c; + c.x = max(-v.x, min(v.x, p.x)); + c.y = max(-v.y, min(v.y, p.y)); + c.z = max(0.0f, p.z); + + float f_dist = len(p - c) / sqrtf((v.x * v.x + v.y * v.y) * 0.5f); + + if (f_dist > 0.0f) { + res += res * f_dist * (offscreen_dicing_scale - 1.0f); + } + } + } + else if (type == CAMERA_PERSPECTIVE) { + /* Calculate as if point is directly ahead of the camera. */ + float3 raster = make_float3(0.5f * full_width, 0.5f * full_height, 0.0f); + float3 Pcamera = transform_perspective(&full_rastertocamera, raster); + + /* dDdx */ + float3 Ddiff = transform_direction(&cameratoworld, Pcamera); + float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy; + float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff); + + /* dPdx */ + float dist = len(transform_point(&worldtocamera, P)); + float3 D = normalize(Ddiff); + res = len(dist * dDdx - dot(dist * dDdx, D) * D); + + /* Decent approx distance to frustum (doesn't handle corners correctly, but not that big of a deal) */ + float f_dist = 0.0f; + + if (offscreen_dicing_scale > 1.0f) { + float3 p = transform_point(&worldtocamera, P); + + /* Distance from the four planes */ + float r = dot(p, frustum_right_normal); + float t = dot(p, frustum_top_normal); + p = make_float3(-p.x, -p.y, p.z); + float l = dot(p, frustum_right_normal); + float b = dot(p, frustum_top_normal); + p = make_float3(-p.x, -p.y, p.z); + + if (r <= 0.0f && l <= 0.0f && t <= 0.0f && b <= 0.0f) { + /* Point is inside frustum */ + f_dist = 0.0f; + } + else if (r > 0.0f && l > 0.0f && t > 0.0f && b > 0.0f) { + /* Point is behind frustum */ + f_dist = len(p); + } + else { + /* Point may be behind or off to the side, need to check */ + float3 along_right = make_float3(-frustum_right_normal.z, 0.0f, frustum_right_normal.x); + float3 along_left = make_float3(frustum_right_normal.z, 0.0f, frustum_right_normal.x); + float3 along_top = make_float3(0.0f, -frustum_top_normal.z, frustum_top_normal.y); + float3 along_bottom = make_float3(0.0f, frustum_top_normal.z, frustum_top_normal.y); + + float dist[] = {r, l, t, b}; + float3 along[] = {along_right, along_left, along_top, along_bottom}; + + bool test_o = false; + + float *d = dist; + float3 *a = along; + for (int i = 0; i < 4; i++, d++, a++) { + /* Test if we should check this side at all */ + if (*d > 0.0f) { + if (dot(p, *a) >= 0.0f) { + /* We are in front of the back edge of this side of the frustum */ + f_dist = max(f_dist, *d); + } + else { + /* Possibly far enough behind the frustum to use distance to origin instead of edge */ + test_o = true; + } + } + } + + if (test_o) { + f_dist = (f_dist > 0) ? min(f_dist, len(p)) : len(p); + } + } + + if (f_dist > 0.0f) { + res += len(dDdx - dot(dDdx, D) * D) * f_dist * (offscreen_dicing_scale - 1.0f); + } + } + } + else if (type == CAMERA_PANORAMA) { + float3 D = transform_point(&worldtocamera, P); + float dist = len(D); + + Ray ray = {{0}}; + + /* Distortion can become so great that the results become meaningless, there + * may be a better way to do this, but calculating differentials from the + * point directly ahead seems to produce good enough results. */ #if 0 - float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D)); - float3 raster = transform_perspective(&full_cameratoraster, make_float3(dir.x, dir.y, 0.0f)); - - ray.t = 1.0f; - camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray); - if(ray.t == 0.0f) { - /* No differentials, just use from directly ahead. */ - camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*full_width, 0.5f*full_height, 0.0f, 0.0f, &ray); - } + float2 dir = direction_to_panorama(&kernel_camera, kernel_camera_motion.data(), normalize(D)); + float3 raster = transform_perspective(&full_cameratoraster, make_float3(dir.x, dir.y, 0.0f)); + + ray.t = 1.0f; + camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), raster.x, raster.y, 0.0f, 0.0f, &ray); + if(ray.t == 0.0f) { + /* No differentials, just use from directly ahead. */ + camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*full_width, 0.5f*full_height, 0.0f, 0.0f, &ray); + } #else - camera_sample_panorama(&kernel_camera, kernel_camera_motion.data(), 0.5f*full_width, 0.5f*full_height, 0.0f, 0.0f, &ray); + camera_sample_panorama(&kernel_camera, + kernel_camera_motion.data(), + 0.5f * full_width, + 0.5f * full_height, + 0.0f, + 0.0f, + &ray); #endif - differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist); + differential_transfer(&ray.dP, ray.dP, ray.D, ray.dD, ray.D, dist); - return max(len(ray.dP.dx),len(ray.dP.dy)); - } + return max(len(ray.dP.dx), len(ray.dP.dy)); + } - return res; + return res; } bool Camera::use_motion() const { - return motion.size() > 1; + return motion.size() > 1; } float Camera::motion_time(int step) const { - return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f; + return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f; } int Camera::motion_step(float time) const { - if(use_motion()) { - for(int step = 0; step < motion.size(); step++) { - if(time == motion_time(step)) { - return step; - } - } - } - - return -1; + if (use_motion()) { + for (int step = 0; step < motion.size(); step++) { + if (time == motion_time(step)) { + return step; + } + } + } + + return -1; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 961e8f918ea..0e91fa44a5b 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -40,179 +40,179 @@ class Scene; */ class Camera : public Node { -public: - NODE_DECLARE - - /* Specifies an offset for the shutter's time interval. */ - enum MotionPosition { - /* Shutter opens at the current frame. */ - MOTION_POSITION_START = 0, - /* Shutter is fully open at the current frame. */ - MOTION_POSITION_CENTER = 1, - /* Shutter closes at the current frame. */ - MOTION_POSITION_END = 2, - - MOTION_NUM_POSITIONS, - }; - - /* Specifies rolling shutter effect. */ - enum RollingShutterType { - /* No rolling shutter effect. */ - ROLLING_SHUTTER_NONE = 0, - /* Sensor is being scanned vertically from top to bottom. */ - ROLLING_SHUTTER_TOP = 1, - - ROLLING_SHUTTER_NUM_TYPES, - }; - - /* Stereo Type */ - enum StereoEye { - STEREO_NONE, - STEREO_LEFT, - STEREO_RIGHT, - }; - - /* motion blur */ - float shuttertime; - MotionPosition motion_position; - array<float> shutter_curve; - size_t shutter_table_offset; - - /* ** Rolling shutter effect. ** */ - /* Defines rolling shutter effect type. */ - RollingShutterType rolling_shutter_type; - /* Specifies exposure time of scanlines when using - * rolling shutter effect. - */ - float rolling_shutter_duration; - - /* depth of field */ - float focaldistance; - float aperturesize; - uint blades; - float bladesrotation; - - /* type */ - CameraType type; - float fov; - - /* panorama */ - PanoramaType panorama_type; - float fisheye_fov; - float fisheye_lens; - float latitude_min; - float latitude_max; - float longitude_min; - float longitude_max; - - /* panorama stereo */ - StereoEye stereo_eye; - bool use_spherical_stereo; - float interocular_distance; - float convergence_distance; - bool use_pole_merge; - float pole_merge_angle_from; - float pole_merge_angle_to; - - /* anamorphic lens bokeh */ - float aperture_ratio; - - /* sensor */ - float sensorwidth; - float sensorheight; - - /* clipping */ - float nearclip; - float farclip; - - /* screen */ - int width, height; - int resolution; - BoundBox2D viewplane; - /* width and height change during preview, so we need these for calculating dice rates. */ - int full_width, full_height; - /* controls how fast the dicing rate falls off for geometry out side of view */ - float offscreen_dicing_scale; - - /* border */ - BoundBox2D border; - BoundBox2D viewport_camera_border; - - /* transformation */ - Transform matrix; - - /* motion */ - array<Transform> motion; - bool use_perspective_motion; - float fov_pre, fov_post; - - /* computed camera parameters */ - ProjectionTransform screentoworld; - ProjectionTransform rastertoworld; - ProjectionTransform ndctoworld; - Transform cameratoworld; - - ProjectionTransform worldtoraster; - ProjectionTransform worldtoscreen; - ProjectionTransform worldtondc; - Transform worldtocamera; - - ProjectionTransform rastertocamera; - ProjectionTransform cameratoraster; - - ProjectionTransform full_rastertocamera; - - float3 dx; - float3 dy; - - float3 full_dx; - float3 full_dy; - - float3 frustum_right_normal; - float3 frustum_top_normal; - - /* update */ - bool need_update; - bool need_device_update; - bool need_flags_update; - int previous_need_motion; - - /* Kernel camera data, copied here for dicing. */ - KernelCamera kernel_camera; - array<DecomposedTransform> kernel_camera_motion; - - /* functions */ - Camera(); - ~Camera(); - - void compute_auto_viewplane(); - - void update(Scene *scene); - - void device_update(Device *device, DeviceScene *dscene, Scene *scene); - void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene, Scene *scene); - - bool modified(const Camera& cam); - bool motion_modified(const Camera& cam); - void tag_update(); - - /* Public utility functions. */ - BoundBox viewplane_bounds_get(); - - /* Calculates the width of a pixel at point in world space. */ - float world_to_raster_size(float3 P); - - /* Motion blur. */ - float motion_time(int step) const; - int motion_step(float time) const; - bool use_motion() const; - -private: - /* Private utility functions. */ - float3 transform_raster_to_world(float raster_x, float raster_y); + public: + NODE_DECLARE + + /* Specifies an offset for the shutter's time interval. */ + enum MotionPosition { + /* Shutter opens at the current frame. */ + MOTION_POSITION_START = 0, + /* Shutter is fully open at the current frame. */ + MOTION_POSITION_CENTER = 1, + /* Shutter closes at the current frame. */ + MOTION_POSITION_END = 2, + + MOTION_NUM_POSITIONS, + }; + + /* Specifies rolling shutter effect. */ + enum RollingShutterType { + /* No rolling shutter effect. */ + ROLLING_SHUTTER_NONE = 0, + /* Sensor is being scanned vertically from top to bottom. */ + ROLLING_SHUTTER_TOP = 1, + + ROLLING_SHUTTER_NUM_TYPES, + }; + + /* Stereo Type */ + enum StereoEye { + STEREO_NONE, + STEREO_LEFT, + STEREO_RIGHT, + }; + + /* motion blur */ + float shuttertime; + MotionPosition motion_position; + array<float> shutter_curve; + size_t shutter_table_offset; + + /* ** Rolling shutter effect. ** */ + /* Defines rolling shutter effect type. */ + RollingShutterType rolling_shutter_type; + /* Specifies exposure time of scanlines when using + * rolling shutter effect. + */ + float rolling_shutter_duration; + + /* depth of field */ + float focaldistance; + float aperturesize; + uint blades; + float bladesrotation; + + /* type */ + CameraType type; + float fov; + + /* panorama */ + PanoramaType panorama_type; + float fisheye_fov; + float fisheye_lens; + float latitude_min; + float latitude_max; + float longitude_min; + float longitude_max; + + /* panorama stereo */ + StereoEye stereo_eye; + bool use_spherical_stereo; + float interocular_distance; + float convergence_distance; + bool use_pole_merge; + float pole_merge_angle_from; + float pole_merge_angle_to; + + /* anamorphic lens bokeh */ + float aperture_ratio; + + /* sensor */ + float sensorwidth; + float sensorheight; + + /* clipping */ + float nearclip; + float farclip; + + /* screen */ + int width, height; + int resolution; + BoundBox2D viewplane; + /* width and height change during preview, so we need these for calculating dice rates. */ + int full_width, full_height; + /* controls how fast the dicing rate falls off for geometry out side of view */ + float offscreen_dicing_scale; + + /* border */ + BoundBox2D border; + BoundBox2D viewport_camera_border; + + /* transformation */ + Transform matrix; + + /* motion */ + array<Transform> motion; + bool use_perspective_motion; + float fov_pre, fov_post; + + /* computed camera parameters */ + ProjectionTransform screentoworld; + ProjectionTransform rastertoworld; + ProjectionTransform ndctoworld; + Transform cameratoworld; + + ProjectionTransform worldtoraster; + ProjectionTransform worldtoscreen; + ProjectionTransform worldtondc; + Transform worldtocamera; + + ProjectionTransform rastertocamera; + ProjectionTransform cameratoraster; + + ProjectionTransform full_rastertocamera; + + float3 dx; + float3 dy; + + float3 full_dx; + float3 full_dy; + + float3 frustum_right_normal; + float3 frustum_top_normal; + + /* update */ + bool need_update; + bool need_device_update; + bool need_flags_update; + int previous_need_motion; + + /* Kernel camera data, copied here for dicing. */ + KernelCamera kernel_camera; + array<DecomposedTransform> kernel_camera_motion; + + /* functions */ + Camera(); + ~Camera(); + + void compute_auto_viewplane(); + + void update(Scene *scene); + + void device_update(Device *device, DeviceScene *dscene, Scene *scene); + void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene); + void device_free(Device *device, DeviceScene *dscene, Scene *scene); + + bool modified(const Camera &cam); + bool motion_modified(const Camera &cam); + void tag_update(); + + /* Public utility functions. */ + BoundBox viewplane_bounds_get(); + + /* Calculates the width of a pixel at point in world space. */ + float world_to_raster_size(float3 P); + + /* Motion blur. */ + float motion_time(int step) const; + int motion_step(float time) const; + bool use_motion() const; + + private: + /* Private utility functions. */ + float3 transform_raster_to_world(float raster_x, float raster_y); }; CCL_NAMESPACE_END -#endif /* __CAMERA_H__ */ +#endif /* __CAMERA_H__ */ diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp index 98c3e99996c..e475ff60eef 100644 --- a/intern/cycles/render/constant_fold.cpp +++ b/intern/cycles/render/constant_fold.cpp @@ -22,371 +22,374 @@ CCL_NAMESPACE_BEGIN -ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output, Scene *scene) -: graph(graph), node(node), output(output), scene(scene) +ConstantFolder::ConstantFolder(ShaderGraph *graph, + ShaderNode *node, + ShaderOutput *output, + Scene *scene) + : graph(graph), node(node), output(output), scene(scene) { } bool ConstantFolder::all_inputs_constant() const { - foreach(ShaderInput *input, node->inputs) { - if(input->link) { - return false; - } - } + foreach (ShaderInput *input, node->inputs) { + if (input->link) { + return false; + } + } - return true; + return true; } void ConstantFolder::make_constant(float value) const { - VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value << ")."; + VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value + << ")."; - foreach(ShaderInput *sock, output->links) { - sock->set(value); - } + foreach (ShaderInput *sock, output->links) { + sock->set(value); + } - graph->disconnect(output); + graph->disconnect(output); } void ConstantFolder::make_constant(float3 value) const { - VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << "."; + VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << "."; - foreach(ShaderInput *sock, output->links) { - sock->set(value); - } + foreach (ShaderInput *sock, output->links) { + sock->set(value); + } - graph->disconnect(output); + graph->disconnect(output); } void ConstantFolder::make_constant_clamp(float value, bool clamp) const { - make_constant(clamp ? saturate(value) : value); + make_constant(clamp ? saturate(value) : value); } void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const { - if(clamp) { - value.x = saturate(value.x); - value.y = saturate(value.y); - value.z = saturate(value.z); - } + if (clamp) { + value.x = saturate(value.x); + value.y = saturate(value.y); + value.z = saturate(value.z); + } - make_constant(value); + make_constant(value); } void ConstantFolder::make_zero() const { - if(output->type() == SocketType::FLOAT) { - make_constant(0.0f); - } - else if(SocketType::is_float3(output->type())) { - make_constant(make_float3(0.0f, 0.0f, 0.0f)); - } - else { - assert(0); - } + if (output->type() == SocketType::FLOAT) { + make_constant(0.0f); + } + else if (SocketType::is_float3(output->type())) { + make_constant(make_float3(0.0f, 0.0f, 0.0f)); + } + else { + assert(0); + } } void ConstantFolder::make_one() const { - if(output->type() == SocketType::FLOAT) { - make_constant(1.0f); - } - else if(SocketType::is_float3(output->type())) { - make_constant(make_float3(1.0f, 1.0f, 1.0f)); - } - else { - assert(0); - } + if (output->type() == SocketType::FLOAT) { + make_constant(1.0f); + } + else if (SocketType::is_float3(output->type())) { + make_constant(make_float3(1.0f, 1.0f, 1.0f)); + } + else { + assert(0); + } } void ConstantFolder::bypass(ShaderOutput *new_output) const { - assert(new_output); + assert(new_output); - VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket " << new_output->parent->name << "::" << new_output->name() << "."; + VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket " + << new_output->parent->name << "::" << new_output->name() << "."; - /* Remove all outgoing links from socket and connect them to new_output instead. - * The graph->relink method affects node inputs, so it's not safe to use in constant - * folding if the node has multiple outputs and will thus be folded multiple times. */ - vector<ShaderInput*> outputs = output->links; + /* Remove all outgoing links from socket and connect them to new_output instead. + * The graph->relink method affects node inputs, so it's not safe to use in constant + * folding if the node has multiple outputs and will thus be folded multiple times. */ + vector<ShaderInput *> outputs = output->links; - graph->disconnect(output); + graph->disconnect(output); - foreach(ShaderInput *sock, outputs) { - graph->connect(new_output, sock); - } + foreach (ShaderInput *sock, outputs) { + graph->connect(new_output, sock); + } } void ConstantFolder::discard() const { - assert(output->type() == SocketType::CLOSURE); + assert(output->type() == SocketType::CLOSURE); - VLOG(1) << "Discarding closure " << node->name << "."; + VLOG(1) << "Discarding closure " << node->name << "."; - graph->disconnect(output); + graph->disconnect(output); } void ConstantFolder::bypass_or_discard(ShaderInput *input) const { - assert(input->type() == SocketType::CLOSURE); - - if(input->link) { - bypass(input->link); - } - else { - discard(); - } + assert(input->type() == SocketType::CLOSURE); + + if (input->link) { + bypass(input->link); + } + else { + discard(); + } } bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const { - if(input->type() != output->type()) { - return false; - } - else if(!input->link) { - if(input->type() == SocketType::FLOAT) { - make_constant_clamp(node->get_float(input->socket_type), clamp); - return true; - } - else if(SocketType::is_float3(input->type())) { - make_constant_clamp(node->get_float3(input->socket_type), clamp); - return true; - } - } - else if(!clamp) { - bypass(input->link); - return true; - } - else { - /* disconnect other inputs if we can't fully bypass due to clamp */ - foreach(ShaderInput *other, node->inputs) { - if(other != input && other->link) { - graph->disconnect(other); - } - } - } - - return false; + if (input->type() != output->type()) { + return false; + } + else if (!input->link) { + if (input->type() == SocketType::FLOAT) { + make_constant_clamp(node->get_float(input->socket_type), clamp); + return true; + } + else if (SocketType::is_float3(input->type())) { + make_constant_clamp(node->get_float3(input->socket_type), clamp); + return true; + } + } + else if (!clamp) { + bypass(input->link); + return true; + } + else { + /* disconnect other inputs if we can't fully bypass due to clamp */ + foreach (ShaderInput *other, node->inputs) { + if (other != input && other->link) { + graph->disconnect(other); + } + } + } + + return false; } bool ConstantFolder::is_zero(ShaderInput *input) const { - if(!input->link) { - if(input->type() == SocketType::FLOAT) { - return node->get_float(input->socket_type) == 0.0f; - } - else if(SocketType::is_float3(input->type())) { - return node->get_float3(input->socket_type) == - make_float3(0.0f, 0.0f, 0.0f); - } - } - - return false; + if (!input->link) { + if (input->type() == SocketType::FLOAT) { + return node->get_float(input->socket_type) == 0.0f; + } + else if (SocketType::is_float3(input->type())) { + return node->get_float3(input->socket_type) == make_float3(0.0f, 0.0f, 0.0f); + } + } + + return false; } bool ConstantFolder::is_one(ShaderInput *input) const { - if(!input->link) { - if(input->type() == SocketType::FLOAT) { - return node->get_float(input->socket_type) == 1.0f; - } - else if(SocketType::is_float3(input->type())) { - return node->get_float3(input->socket_type) == - make_float3(1.0f, 1.0f, 1.0f); - } - } - - return false; + if (!input->link) { + if (input->type() == SocketType::FLOAT) { + return node->get_float(input->socket_type) == 1.0f; + } + else if (SocketType::is_float3(input->type())) { + return node->get_float3(input->socket_type) == make_float3(1.0f, 1.0f, 1.0f); + } + } + + return false; } /* Specific nodes */ void ConstantFolder::fold_mix(NodeMix type, bool clamp) const { - ShaderInput *fac_in = node->input("Fac"); - ShaderInput *color1_in = node->input("Color1"); - ShaderInput *color2_in = node->input("Color2"); - - float fac = saturate(node->get_float(fac_in->socket_type)); - bool fac_is_zero = !fac_in->link && fac == 0.0f; - bool fac_is_one = !fac_in->link && fac == 1.0f; - - /* remove no-op node when factor is 0.0 */ - if(fac_is_zero) { - /* note that some of the modes will clamp out of bounds values even without use_clamp */ - if(!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { - if(try_bypass_or_make_constant(color1_in, clamp)) { - return; - } - } - } - - switch(type) { - case NODE_MIX_BLEND: - /* remove useless mix colors nodes */ - if(color1_in->link && color2_in->link) { - if(color1_in->link == color2_in->link) { - try_bypass_or_make_constant(color1_in, clamp); - break; - } - } - else if(!color1_in->link && !color2_in->link) { - float3 color1 = node->get_float3(color1_in->socket_type); - float3 color2 = node->get_float3(color2_in->socket_type); - if(color1 == color2) { - try_bypass_or_make_constant(color1_in, clamp); - break; - } - } - /* remove no-op mix color node when factor is 1.0 */ - if(fac_is_one) { - try_bypass_or_make_constant(color2_in, clamp); - break; - } - break; - case NODE_MIX_ADD: - /* 0 + X (fac 1) == X */ - if(is_zero(color1_in) && fac_is_one) { - try_bypass_or_make_constant(color2_in, clamp); - } - /* X + 0 (fac ?) == X */ - else if(is_zero(color2_in)) { - try_bypass_or_make_constant(color1_in, clamp); - } - break; - case NODE_MIX_SUB: - /* X - 0 (fac ?) == X */ - if(is_zero(color2_in)) { - try_bypass_or_make_constant(color1_in, clamp); - } - /* X - X (fac 1) == 0 */ - else if(color1_in->link && color1_in->link == color2_in->link && fac_is_one) { - make_zero(); - } - break; - case NODE_MIX_MUL: - /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ - if(is_one(color1_in) && fac_is_one) { - try_bypass_or_make_constant(color2_in, clamp); - } - else if(is_one(color2_in)) { - try_bypass_or_make_constant(color1_in, clamp); - } - /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */ - else if(is_zero(color1_in)) { - make_zero(); - } - else if(is_zero(color2_in) && fac_is_one) { - make_zero(); - } - break; - case NODE_MIX_DIV: - /* X / 1 (fac ?) == X */ - if(is_one(color2_in)) { - try_bypass_or_make_constant(color1_in, clamp); - } - /* 0 / ? (fac ?) == 0 */ - else if(is_zero(color1_in)) { - make_zero(); - } - break; - default: - break; - } + ShaderInput *fac_in = node->input("Fac"); + ShaderInput *color1_in = node->input("Color1"); + ShaderInput *color2_in = node->input("Color2"); + + float fac = saturate(node->get_float(fac_in->socket_type)); + bool fac_is_zero = !fac_in->link && fac == 0.0f; + bool fac_is_one = !fac_in->link && fac == 1.0f; + + /* remove no-op node when factor is 0.0 */ + if (fac_is_zero) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { + if (try_bypass_or_make_constant(color1_in, clamp)) { + return; + } + } + } + + switch (type) { + case NODE_MIX_BLEND: + /* remove useless mix colors nodes */ + if (color1_in->link && color2_in->link) { + if (color1_in->link == color2_in->link) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + else if (!color1_in->link && !color2_in->link) { + float3 color1 = node->get_float3(color1_in->socket_type); + float3 color2 = node->get_float3(color2_in->socket_type); + if (color1 == color2) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + /* remove no-op mix color node when factor is 1.0 */ + if (fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + break; + } + break; + case NODE_MIX_ADD: + /* 0 + X (fac 1) == X */ + if (is_zero(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + /* X + 0 (fac ?) == X */ + else if (is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + break; + case NODE_MIX_SUB: + /* X - 0 (fac ?) == X */ + if (is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* X - X (fac 1) == 0 */ + else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_MUL: + /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ + if (is_one(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + else if (is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */ + else if (is_zero(color1_in)) { + make_zero(); + } + else if (is_zero(color2_in) && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_DIV: + /* X / 1 (fac ?) == X */ + if (is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 / ? (fac ?) == 0 */ + else if (is_zero(color1_in)) { + make_zero(); + } + break; + default: + break; + } } void ConstantFolder::fold_math(NodeMath type, bool clamp) const { - ShaderInput *value1_in = node->input("Value1"); - ShaderInput *value2_in = node->input("Value2"); - - switch(type) { - case NODE_MATH_ADD: - /* X + 0 == 0 + X == X */ - if(is_zero(value1_in)) { - try_bypass_or_make_constant(value2_in, clamp); - } - else if(is_zero(value2_in)) { - try_bypass_or_make_constant(value1_in, clamp); - } - break; - case NODE_MATH_SUBTRACT: - /* X - 0 == X */ - if(is_zero(value2_in)) { - try_bypass_or_make_constant(value1_in, clamp); - } - break; - case NODE_MATH_MULTIPLY: - /* X * 1 == 1 * X == X */ - if(is_one(value1_in)) { - try_bypass_or_make_constant(value2_in, clamp); - } - else if(is_one(value2_in)) { - try_bypass_or_make_constant(value1_in, clamp); - } - /* X * 0 == 0 * X == 0 */ - else if(is_zero(value1_in) || is_zero(value2_in)) { - make_zero(); - } - break; - case NODE_MATH_DIVIDE: - /* X / 1 == X */ - if(is_one(value2_in)) { - try_bypass_or_make_constant(value1_in, clamp); - } - /* 0 / X == 0 */ - else if(is_zero(value1_in)) { - make_zero(); - } - break; - case NODE_MATH_POWER: - /* 1 ^ X == X ^ 0 == 1 */ - if(is_one(value1_in) || is_zero(value2_in)) { - make_one(); - } - /* X ^ 1 == X */ - else if(is_one(value2_in)) { - try_bypass_or_make_constant(value1_in, clamp); - } - default: - break; - } + ShaderInput *value1_in = node->input("Value1"); + ShaderInput *value2_in = node->input("Value2"); + + switch (type) { + case NODE_MATH_ADD: + /* X + 0 == 0 + X == X */ + if (is_zero(value1_in)) { + try_bypass_or_make_constant(value2_in, clamp); + } + else if (is_zero(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + break; + case NODE_MATH_SUBTRACT: + /* X - 0 == X */ + if (is_zero(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + break; + case NODE_MATH_MULTIPLY: + /* X * 1 == 1 * X == X */ + if (is_one(value1_in)) { + try_bypass_or_make_constant(value2_in, clamp); + } + else if (is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + /* X * 0 == 0 * X == 0 */ + else if (is_zero(value1_in) || is_zero(value2_in)) { + make_zero(); + } + break; + case NODE_MATH_DIVIDE: + /* X / 1 == X */ + if (is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + /* 0 / X == 0 */ + else if (is_zero(value1_in)) { + make_zero(); + } + break; + case NODE_MATH_POWER: + /* 1 ^ X == X ^ 0 == 1 */ + if (is_one(value1_in) || is_zero(value2_in)) { + make_one(); + } + /* X ^ 1 == X */ + else if (is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + default: + break; + } } void ConstantFolder::fold_vector_math(NodeVectorMath type) const { - ShaderInput *vector1_in = node->input("Vector1"); - ShaderInput *vector2_in = node->input("Vector2"); - - switch(type) { - case NODE_VECTOR_MATH_ADD: - /* X + 0 == 0 + X == X */ - if(is_zero(vector1_in)) { - try_bypass_or_make_constant(vector2_in); - } - else if(is_zero(vector2_in)) { - try_bypass_or_make_constant(vector1_in); - } - break; - case NODE_VECTOR_MATH_SUBTRACT: - /* X - 0 == X */ - if(is_zero(vector2_in)) { - try_bypass_or_make_constant(vector1_in); - } - break; - case NODE_VECTOR_MATH_DOT_PRODUCT: - case NODE_VECTOR_MATH_CROSS_PRODUCT: - /* X * 0 == 0 * X == 0 */ - if(is_zero(vector1_in) || is_zero(vector2_in)) { - make_zero(); - } - break; - default: - break; - } + ShaderInput *vector1_in = node->input("Vector1"); + ShaderInput *vector2_in = node->input("Vector2"); + + switch (type) { + case NODE_VECTOR_MATH_ADD: + /* X + 0 == 0 + X == X */ + if (is_zero(vector1_in)) { + try_bypass_or_make_constant(vector2_in); + } + else if (is_zero(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_SUBTRACT: + /* X - 0 == X */ + if (is_zero(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_DOT_PRODUCT: + case NODE_VECTOR_MATH_CROSS_PRODUCT: + /* X * 0 == 0 * X == 0 */ + if (is_zero(vector1_in) || is_zero(vector2_in)) { + make_zero(); + } + break; + default: + break; + } } CCL_NAMESPACE_END diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h index 6ec94b055e3..c14b94868dc 100644 --- a/intern/cycles/render/constant_fold.h +++ b/intern/cycles/render/constant_fold.h @@ -29,45 +29,45 @@ class ShaderNode; class ShaderOutput; class ConstantFolder { -public: - ShaderGraph *const graph; - ShaderNode *const node; - ShaderOutput *const output; + public: + ShaderGraph *const graph; + ShaderNode *const node; + ShaderOutput *const output; - Scene *scene; + Scene *scene; - ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output, Scene *scene); + ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output, Scene *scene); - bool all_inputs_constant() const; + bool all_inputs_constant() const; - /* Constant folding helpers */ - void make_constant(float value) const; - void make_constant(float3 value) const; - void make_constant_clamp(float value, bool clamp) const; - void make_constant_clamp(float3 value, bool clamp) const; - void make_zero() const; - void make_one() const; + /* Constant folding helpers */ + void make_constant(float value) const; + void make_constant(float3 value) const; + void make_constant_clamp(float value, bool clamp) const; + void make_constant_clamp(float3 value, bool clamp) const; + void make_zero() const; + void make_one() const; - /* Bypass node, relinking to another output socket. */ - void bypass(ShaderOutput *output) const; + /* Bypass node, relinking to another output socket. */ + void bypass(ShaderOutput *output) const; - /* For closure nodes, discard node entirely or bypass to one of its inputs. */ - void discard() const; - void bypass_or_discard(ShaderInput *input) const; + /* For closure nodes, discard node entirely or bypass to one of its inputs. */ + void discard() const; + void bypass_or_discard(ShaderInput *input) const; - /* Bypass or make constant, unless we can't due to clamp being true. */ - bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const; + /* Bypass or make constant, unless we can't due to clamp being true. */ + bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const; - /* Test if shader inputs of the current nodes have fixed values. */ - bool is_zero(ShaderInput *input) const; - bool is_one(ShaderInput *input) const; + /* Test if shader inputs of the current nodes have fixed values. */ + bool is_zero(ShaderInput *input) const; + bool is_one(ShaderInput *input) const; - /* Specific nodes. */ - void fold_mix(NodeMix type, bool clamp) const; - void fold_math(NodeMath type, bool clamp) const; - void fold_vector_math(NodeVectorMath type) const; + /* Specific nodes. */ + void fold_mix(NodeMix type, bool clamp) const; + void fold_math(NodeMath type, bool clamp) const; + void fold_vector_math(NodeVectorMath type) const; }; CCL_NAMESPACE_END -#endif /* __CONSTANT_FOLD_H__ */ +#endif /* __CONSTANT_FOLD_H__ */ diff --git a/intern/cycles/render/coverage.cpp b/intern/cycles/render/coverage.cpp index 72ef4cda3ff..0a29903728a 100644 --- a/intern/cycles/render/coverage.cpp +++ b/intern/cycles/render/coverage.cpp @@ -25,119 +25,128 @@ CCL_NAMESPACE_BEGIN -static bool crypomatte_comp(const pair<float, float>& i, const pair<float, float> j) { return i.first > j.first; } +static bool crypomatte_comp(const pair<float, float> &i, const pair<float, float> j) +{ + return i.first > j.first; +} void Coverage::finalize() { - int pass_offset = 0; - if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { - finalize_buffer(coverage_object, pass_offset); - pass_offset += kernel_data.film.cryptomatte_depth * 4; - } - if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { - finalize_buffer(coverage_material, pass_offset); - pass_offset += kernel_data.film.cryptomatte_depth * 4; - } - if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { - finalize_buffer(coverage_asset, pass_offset); - } + int pass_offset = 0; + if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { + finalize_buffer(coverage_object, pass_offset); + pass_offset += kernel_data.film.cryptomatte_depth * 4; + } + if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { + finalize_buffer(coverage_material, pass_offset); + pass_offset += kernel_data.film.cryptomatte_depth * 4; + } + if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { + finalize_buffer(coverage_asset, pass_offset); + } } void Coverage::init_path_trace() { - kg->coverage_object = kg->coverage_material = kg->coverage_asset = NULL; + kg->coverage_object = kg->coverage_material = kg->coverage_asset = NULL; - if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { - if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { - coverage_object.clear(); - coverage_object.resize(tile.w * tile.h); - } - if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { - coverage_material.clear(); - coverage_material.resize(tile.w * tile.h); - } - if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { - coverage_asset.clear(); - coverage_asset.resize(tile.w * tile.h); - } - } + if (kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { + if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { + coverage_object.clear(); + coverage_object.resize(tile.w * tile.h); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { + coverage_material.clear(); + coverage_material.resize(tile.w * tile.h); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { + coverage_asset.clear(); + coverage_asset.resize(tile.w * tile.h); + } + } } void Coverage::init_pixel(int x, int y) { - if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { - const int pixel_index = tile.w * (y - tile.y) + x - tile.x; - if(kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { - kg->coverage_object = &coverage_object[pixel_index]; - } - if(kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { - kg->coverage_material = &coverage_material[pixel_index]; - } - if(kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { - kg->coverage_asset = &coverage_asset[pixel_index]; - } - } + if (kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { + const int pixel_index = tile.w * (y - tile.y) + x - tile.x; + if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { + kg->coverage_object = &coverage_object[pixel_index]; + } + if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { + kg->coverage_material = &coverage_material[pixel_index]; + } + if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { + kg->coverage_asset = &coverage_asset[pixel_index]; + } + } } -void Coverage::finalize_buffer(vector<CoverageMap> & coverage, const int pass_offset) +void Coverage::finalize_buffer(vector<CoverageMap> &coverage, const int pass_offset) { - if(kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { - flatten_buffer(coverage, pass_offset); - } - else { - sort_buffer(pass_offset); - } + if (kernel_data.film.cryptomatte_passes & CRYPT_ACCURATE) { + flatten_buffer(coverage, pass_offset); + } + else { + sort_buffer(pass_offset); + } } void Coverage::flatten_buffer(vector<CoverageMap> &coverage, const int pass_offset) { - /* Sort the coverage map and write it to the output */ - int pixel_index = 0; - int pass_stride = tile.buffers->params.get_passes_size(); - for(int y = 0; y < tile.h; ++y) { - for(int x = 0; x < tile.w; ++x) { - const CoverageMap& pixel = coverage[pixel_index]; - if(!pixel.empty()) { - /* buffer offset */ - int index = x + y * tile.stride; - float *buffer = (float*)tile.buffer + index*pass_stride; + /* Sort the coverage map and write it to the output */ + int pixel_index = 0; + int pass_stride = tile.buffers->params.get_passes_size(); + for (int y = 0; y < tile.h; ++y) { + for (int x = 0; x < tile.w; ++x) { + const CoverageMap &pixel = coverage[pixel_index]; + if (!pixel.empty()) { + /* buffer offset */ + int index = x + y * tile.stride; + float *buffer = (float *)tile.buffer + index * pass_stride; - /* sort the cryptomatte pixel */ - vector<pair<float, float> > sorted_pixel; - for(CoverageMap::const_iterator it = pixel.begin(); it != pixel.end(); ++it) { - sorted_pixel.push_back(std::make_pair(it->second, it->first)); - } - sort(sorted_pixel.begin(), sorted_pixel.end(), crypomatte_comp); - int num_slots = 2 * (kernel_data.film.cryptomatte_depth); - if(sorted_pixel.size() > num_slots) { - float leftover = 0.0f; - for(vector<pair<float, float> >::iterator it = sorted_pixel.begin()+num_slots; it != sorted_pixel.end(); ++it) { - leftover += it->first; - } - sorted_pixel[num_slots-1].first += leftover; - } - int limit = min(num_slots, sorted_pixel.size()); - for(int i = 0; i < limit; ++i) { - kernel_write_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, 2 * (kernel_data.film.cryptomatte_depth), sorted_pixel[i].second, sorted_pixel[i].first); - } - } - ++pixel_index; - } - } + /* sort the cryptomatte pixel */ + vector<pair<float, float>> sorted_pixel; + for (CoverageMap::const_iterator it = pixel.begin(); it != pixel.end(); ++it) { + sorted_pixel.push_back(std::make_pair(it->second, it->first)); + } + sort(sorted_pixel.begin(), sorted_pixel.end(), crypomatte_comp); + int num_slots = 2 * (kernel_data.film.cryptomatte_depth); + if (sorted_pixel.size() > num_slots) { + float leftover = 0.0f; + for (vector<pair<float, float>>::iterator it = sorted_pixel.begin() + num_slots; + it != sorted_pixel.end(); + ++it) { + leftover += it->first; + } + sorted_pixel[num_slots - 1].first += leftover; + } + int limit = min(num_slots, sorted_pixel.size()); + for (int i = 0; i < limit; ++i) { + kernel_write_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, + 2 * (kernel_data.film.cryptomatte_depth), + sorted_pixel[i].second, + sorted_pixel[i].first); + } + } + ++pixel_index; + } + } } void Coverage::sort_buffer(const int pass_offset) { - /* Sort the coverage map and write it to the output */ - int pass_stride = tile.buffers->params.get_passes_size(); - for(int y = 0; y < tile.h; ++y) { - for(int x = 0; x < tile.w; ++x) { - /* buffer offset */ - int index = x + y*tile.stride; - float *buffer = (float*)tile.buffer + index*pass_stride; - kernel_sort_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, 2 * (kernel_data.film.cryptomatte_depth)); - } - } + /* Sort the coverage map and write it to the output */ + int pass_stride = tile.buffers->params.get_passes_size(); + for (int y = 0; y < tile.h; ++y) { + for (int x = 0; x < tile.w; ++x) { + /* buffer offset */ + int index = x + y * tile.stride; + float *buffer = (float *)tile.buffer + index * pass_stride; + kernel_sort_id_slots(buffer + kernel_data.film.pass_cryptomatte + pass_offset, + 2 * (kernel_data.film.cryptomatte_depth)); + } + } } CCL_NAMESPACE_END diff --git a/intern/cycles/render/coverage.h b/intern/cycles/render/coverage.h index 9ee0bce7517..3d1f6a2b040 100644 --- a/intern/cycles/render/coverage.h +++ b/intern/cycles/render/coverage.h @@ -22,28 +22,30 @@ #include "util/util_vector.h" #ifndef __COVERAGE_H__ -#define __COVERAGE_H__ +# define __COVERAGE_H__ CCL_NAMESPACE_BEGIN class Coverage { -public: - Coverage(KernelGlobals *kg_, RenderTile &tile_) : kg(kg_), tile(tile_) { } - void init_path_trace(); - void init_pixel(int x, int y); - void finalize(); -private: - vector<CoverageMap>coverage_object; - vector<CoverageMap>coverage_material; - vector<CoverageMap>coverage_asset; - KernelGlobals *kg; - RenderTile &tile; - void finalize_buffer(vector<CoverageMap>&coverage, const int pass_offset); - void flatten_buffer(vector<CoverageMap>&coverage, const int pass_offset); - void sort_buffer(const int pass_offset); -}; + public: + Coverage(KernelGlobals *kg_, RenderTile &tile_) : kg(kg_), tile(tile_) + { + } + void init_path_trace(); + void init_pixel(int x, int y); + void finalize(); + private: + vector<CoverageMap> coverage_object; + vector<CoverageMap> coverage_material; + vector<CoverageMap> coverage_asset; + KernelGlobals *kg; + RenderTile &tile; + void finalize_buffer(vector<CoverageMap> &coverage, const int pass_offset); + void flatten_buffer(vector<CoverageMap> &coverage, const int pass_offset); + void sort_buffer(const int pass_offset); +}; CCL_NAMESPACE_END -#endif /* __COVERAGE_H__ */ +#endif /* __COVERAGE_H__ */ diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp index 58b71d3e122..49ab70541c2 100644 --- a/intern/cycles/render/curves.cpp +++ b/intern/cycles/render/curves.cpp @@ -31,72 +31,73 @@ CCL_NAMESPACE_BEGIN void curvebounds(float *lower, float *upper, float3 *p, int dim) { - float *p0 = &p[0].x; - float *p1 = &p[1].x; - float *p2 = &p[2].x; - float *p3 = &p[3].x; - - float fc = 0.71f; - float curve_coef[4]; - curve_coef[0] = p1[dim]; - curve_coef[1] = -fc*p0[dim] + fc*p2[dim]; - curve_coef[2] = 2.0f * fc * p0[dim] + (fc - 3.0f) * p1[dim] + (3.0f - 2.0f * fc) * p2[dim] - fc * p3[dim]; - curve_coef[3] = -fc * p0[dim] + (2.0f - fc) * p1[dim] + (fc - 2.0f) * p2[dim] + fc * p3[dim]; - - float discroot = curve_coef[2] * curve_coef[2] - 3 * curve_coef[3] * curve_coef[1]; - float ta = -1.0f; - float tb = -1.0f; - - if(discroot >= 0) { - discroot = sqrtf(discroot); - ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]); - tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]); - ta = (ta > 1.0f || ta < 0.0f) ? -1.0f : ta; - tb = (tb > 1.0f || tb < 0.0f) ? -1.0f : tb; - } - - *upper = max(p1[dim],p2[dim]); - *lower = min(p1[dim],p2[dim]); - - float exa = p1[dim]; - float exb = p2[dim]; - - if(ta >= 0.0f) { - float t2 = ta * ta; - float t3 = t2 * ta; - exa = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * ta + curve_coef[0]; - } - if(tb >= 0.0f) { - float t2 = tb * tb; - float t3 = t2 * tb; - exb = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * tb + curve_coef[0]; - } - - *upper = max(*upper, max(exa,exb)); - *lower = min(*lower, min(exa,exb)); + float *p0 = &p[0].x; + float *p1 = &p[1].x; + float *p2 = &p[2].x; + float *p3 = &p[3].x; + + float fc = 0.71f; + float curve_coef[4]; + curve_coef[0] = p1[dim]; + curve_coef[1] = -fc * p0[dim] + fc * p2[dim]; + curve_coef[2] = 2.0f * fc * p0[dim] + (fc - 3.0f) * p1[dim] + (3.0f - 2.0f * fc) * p2[dim] - + fc * p3[dim]; + curve_coef[3] = -fc * p0[dim] + (2.0f - fc) * p1[dim] + (fc - 2.0f) * p2[dim] + fc * p3[dim]; + + float discroot = curve_coef[2] * curve_coef[2] - 3 * curve_coef[3] * curve_coef[1]; + float ta = -1.0f; + float tb = -1.0f; + + if (discroot >= 0) { + discroot = sqrtf(discroot); + ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]); + tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]); + ta = (ta > 1.0f || ta < 0.0f) ? -1.0f : ta; + tb = (tb > 1.0f || tb < 0.0f) ? -1.0f : tb; + } + + *upper = max(p1[dim], p2[dim]); + *lower = min(p1[dim], p2[dim]); + + float exa = p1[dim]; + float exb = p2[dim]; + + if (ta >= 0.0f) { + float t2 = ta * ta; + float t3 = t2 * ta; + exa = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * ta + curve_coef[0]; + } + if (tb >= 0.0f) { + float t2 = tb * tb; + float t3 = t2 * tb; + exb = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * tb + curve_coef[0]; + } + + *upper = max(*upper, max(exa, exb)); + *lower = min(*lower, min(exa, exb)); } /* Hair System Manager */ CurveSystemManager::CurveSystemManager() { - primitive = CURVE_LINE_SEGMENTS; - curve_shape = CURVE_THICK; - line_method = CURVE_CORRECTED; - triangle_method = CURVE_CAMERA_TRIANGLES; - resolution = 3; - subdivisions = 3; - - minimum_width = 0.0f; - maximum_width = 0.0f; - - use_curves = true; - use_encasing = true; - use_backfacing = false; - use_tangent_normal_geometry = false; - - need_update = true; - need_mesh_update = false; + primitive = CURVE_LINE_SEGMENTS; + curve_shape = CURVE_THICK; + line_method = CURVE_CORRECTED; + triangle_method = CURVE_CAMERA_TRIANGLES; + resolution = 3; + subdivisions = 3; + + minimum_width = 0.0f; + maximum_width = 0.0f; + + use_curves = true; + use_encasing = true; + use_backfacing = false; + use_tangent_normal_geometry = false; + + need_update = true; + need_mesh_update = false; } CurveSystemManager::~CurveSystemManager() @@ -106,85 +107,82 @@ CurveSystemManager::~CurveSystemManager() void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scene * /*scene*/, - Progress& progress) + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - device_free(device, dscene); + device_free(device, dscene); - progress.set_status("Updating Hair settings", "Copying Hair settings to device"); + progress.set_status("Updating Hair settings", "Copying Hair settings to device"); - KernelCurves *kcurve = &dscene->data.curve; + KernelCurves *kcurve = &dscene->data.curve; - kcurve->curveflags = 0; + kcurve->curveflags = 0; - if(use_curves) { - if(primitive == CURVE_SEGMENTS || primitive == CURVE_RIBBONS) - kcurve->curveflags |= CURVE_KN_INTERPOLATE; - if(primitive == CURVE_RIBBONS) - kcurve->curveflags |= CURVE_KN_RIBBONS; + if (use_curves) { + if (primitive == CURVE_SEGMENTS || primitive == CURVE_RIBBONS) + kcurve->curveflags |= CURVE_KN_INTERPOLATE; + if (primitive == CURVE_RIBBONS) + kcurve->curveflags |= CURVE_KN_RIBBONS; - if(line_method == CURVE_ACCURATE) - kcurve->curveflags |= CURVE_KN_ACCURATE; - else if(line_method == CURVE_CORRECTED) - kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION; + if (line_method == CURVE_ACCURATE) + kcurve->curveflags |= CURVE_KN_ACCURATE; + else if (line_method == CURVE_CORRECTED) + kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION; - if(use_tangent_normal_geometry) - kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL; - if(use_backfacing) - kcurve->curveflags |= CURVE_KN_BACKFACING; - if(use_encasing) - kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER; + if (use_tangent_normal_geometry) + kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL; + if (use_backfacing) + kcurve->curveflags |= CURVE_KN_BACKFACING; + if (use_encasing) + kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER; - kcurve->minimum_width = minimum_width; - kcurve->maximum_width = maximum_width; - kcurve->subdivisions = subdivisions; - } + kcurve->minimum_width = minimum_width; + kcurve->maximum_width = maximum_width; + kcurve->subdivisions = subdivisions; + } - if(progress.get_cancel()) return; + if (progress.get_cancel()) + return; - need_update = false; + need_update = false; } -void CurveSystemManager::device_free(Device * /*device*/, - DeviceScene * /*dscene*/) +void CurveSystemManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/) { - } -bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager) +bool CurveSystemManager::modified(const CurveSystemManager &CurveSystemManager) { - return !(curve_shape == CurveSystemManager.curve_shape && - line_method == CurveSystemManager.line_method && - primitive == CurveSystemManager.primitive && - use_encasing == CurveSystemManager.use_encasing && - use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry && - minimum_width == CurveSystemManager.minimum_width && - maximum_width == CurveSystemManager.maximum_width && - use_backfacing == CurveSystemManager.use_backfacing && - triangle_method == CurveSystemManager.triangle_method && - resolution == CurveSystemManager.resolution && - use_curves == CurveSystemManager.use_curves && - subdivisions == CurveSystemManager.subdivisions); + return !( + curve_shape == CurveSystemManager.curve_shape && + line_method == CurveSystemManager.line_method && primitive == CurveSystemManager.primitive && + use_encasing == CurveSystemManager.use_encasing && + use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry && + minimum_width == CurveSystemManager.minimum_width && + maximum_width == CurveSystemManager.maximum_width && + use_backfacing == CurveSystemManager.use_backfacing && + triangle_method == CurveSystemManager.triangle_method && + resolution == CurveSystemManager.resolution && use_curves == CurveSystemManager.use_curves && + subdivisions == CurveSystemManager.subdivisions); } -bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager) +bool CurveSystemManager::modified_mesh(const CurveSystemManager &CurveSystemManager) { - return !(primitive == CurveSystemManager.primitive && - curve_shape == CurveSystemManager.curve_shape && - triangle_method == CurveSystemManager.triangle_method && - resolution == CurveSystemManager.resolution && - use_curves == CurveSystemManager.use_curves); + return !( + primitive == CurveSystemManager.primitive && curve_shape == CurveSystemManager.curve_shape && + triangle_method == CurveSystemManager.triangle_method && + resolution == CurveSystemManager.resolution && use_curves == CurveSystemManager.use_curves); } void CurveSystemManager::tag_update(Scene * /*scene*/) { - need_update = true; + need_update = true; } void CurveSystemManager::tag_update_mesh() { - need_mesh_update = true; + need_mesh_update = true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h index 9db411bc04b..81e7b4ac88d 100644 --- a/intern/cycles/render/curves.h +++ b/intern/cycles/render/curves.h @@ -30,93 +30,91 @@ class Scene; void curvebounds(float *lower, float *upper, float3 *p, int dim); typedef enum CurvePrimitiveType { - CURVE_TRIANGLES = 0, - CURVE_LINE_SEGMENTS = 1, - CURVE_SEGMENTS = 2, - CURVE_RIBBONS = 3, + CURVE_TRIANGLES = 0, + CURVE_LINE_SEGMENTS = 1, + CURVE_SEGMENTS = 2, + CURVE_RIBBONS = 3, - CURVE_NUM_PRIMITIVE_TYPES, + CURVE_NUM_PRIMITIVE_TYPES, } CurvePrimitiveType; typedef enum CurveShapeType { - CURVE_RIBBON = 0, - CURVE_THICK = 1, + CURVE_RIBBON = 0, + CURVE_THICK = 1, - CURVE_NUM_SHAPE_TYPES, + CURVE_NUM_SHAPE_TYPES, } CurveShapeType; typedef enum CurveTriangleMethod { - CURVE_CAMERA_TRIANGLES, - CURVE_TESSELATED_TRIANGLES + CURVE_CAMERA_TRIANGLES, + CURVE_TESSELATED_TRIANGLES } CurveTriangleMethod; typedef enum CurveLineMethod { - CURVE_ACCURATE, - CURVE_CORRECTED, - CURVE_UNCORRECTED + CURVE_ACCURATE, + CURVE_CORRECTED, + CURVE_UNCORRECTED } CurveLineMethod; class ParticleCurveData { -public: + public: + ParticleCurveData(); + ~ParticleCurveData(); - ParticleCurveData(); - ~ParticleCurveData(); + array<int> psys_firstcurve; + array<int> psys_curvenum; + array<int> psys_shader; - array<int> psys_firstcurve; - array<int> psys_curvenum; - array<int> psys_shader; + array<float> psys_rootradius; + array<float> psys_tipradius; + array<float> psys_shape; + array<bool> psys_closetip; - array<float> psys_rootradius; - array<float> psys_tipradius; - array<float> psys_shape; - array<bool> psys_closetip; + array<int> curve_firstkey; + array<int> curve_keynum; + array<float> curve_length; + array<float2> curve_uv; + array<float3> curve_vcol; - array<int> curve_firstkey; - array<int> curve_keynum; - array<float> curve_length; - array<float2> curve_uv; - array<float3> curve_vcol; - - array<float3> curvekey_co; - array<float> curvekey_time; + array<float3> curvekey_co; + array<float> curvekey_time; }; /* HairSystem Manager */ class CurveSystemManager { -public: - - CurvePrimitiveType primitive; - CurveShapeType curve_shape; - CurveLineMethod line_method; - CurveTriangleMethod triangle_method; - int resolution; - int subdivisions; - - float minimum_width; - float maximum_width; - - bool use_curves; - bool use_encasing; - bool use_backfacing; - bool use_tangent_normal_geometry; - - bool need_update; - bool need_mesh_update; - - CurveSystemManager(); - ~CurveSystemManager(); - - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_free(Device *device, DeviceScene *dscene); - bool modified(const CurveSystemManager& CurveSystemManager); - bool modified_mesh(const CurveSystemManager& CurveSystemManager); - - void tag_update(Scene *scene); - void tag_update_mesh(); + public: + CurvePrimitiveType primitive; + CurveShapeType curve_shape; + CurveLineMethod line_method; + CurveTriangleMethod triangle_method; + int resolution; + int subdivisions; + + float minimum_width; + float maximum_width; + + bool use_curves; + bool use_encasing; + bool use_backfacing; + bool use_tangent_normal_geometry; + + bool need_update; + bool need_mesh_update; + + CurveSystemManager(); + ~CurveSystemManager(); + + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free(Device *device, DeviceScene *dscene); + bool modified(const CurveSystemManager &CurveSystemManager); + bool modified_mesh(const CurveSystemManager &CurveSystemManager); + + void tag_update(Scene *scene); + void tag_update_mesh(); }; CCL_NAMESPACE_END -#endif /* __CURVES_H__ */ +#endif /* __CURVES_H__ */ diff --git a/intern/cycles/render/denoising.cpp b/intern/cycles/render/denoising.cpp index ab74fd8fd38..c4f21d9c771 100644 --- a/intern/cycles/render/denoising.cpp +++ b/intern/cycles/render/denoising.cpp @@ -31,55 +31,55 @@ CCL_NAMESPACE_BEGIN static void print_progress(int num, int total, int frame, int num_frames) { - const char *label = "Denoise Frame "; - int cols = system_console_width(); - - cols -= strlen(label); - - int len = 1; - for(int x = total; x > 9; x /= 10) { - len++; - } - - int bars = cols - 2*len - 6; - - printf("\r%s", label); - - if(num_frames > 1) { - int frame_len = 1; - for(int x = num_frames - 1; x > 9; x /= 10) { - frame_len++; - } - bars -= frame_len + 2; - printf("%*d ", frame_len, frame); - } - - int v = int(float(num)*bars/total); - printf("["); - for(int i = 0; i < v; i++) { - printf("="); - } - if(v < bars) { - printf(">"); - } - for(int i = v+1; i < bars; i++) { - printf(" "); - } - printf(string_printf("] %%%dd / %d", len, total).c_str(), num); - fflush(stdout); + const char *label = "Denoise Frame "; + int cols = system_console_width(); + + cols -= strlen(label); + + int len = 1; + for (int x = total; x > 9; x /= 10) { + len++; + } + + int bars = cols - 2 * len - 6; + + printf("\r%s", label); + + if (num_frames > 1) { + int frame_len = 1; + for (int x = num_frames - 1; x > 9; x /= 10) { + frame_len++; + } + bars -= frame_len + 2; + printf("%*d ", frame_len, frame); + } + + int v = int(float(num) * bars / total); + printf("["); + for (int i = 0; i < v; i++) { + printf("="); + } + if (v < bars) { + printf(">"); + } + for (int i = v + 1; i < bars; i++) { + printf(" "); + } + printf(string_printf("] %%%dd / %d", len, total).c_str(), num); + fflush(stdout); } /* Splits in at its last dot, setting suffix to the part after the dot and in to the part before it. * Returns whether a dot was found. */ static bool split_last_dot(string &in, string &suffix) { - size_t pos = in.rfind("."); - if(pos == string::npos) { - return false; - } - suffix = in.substr(pos+1); - in = in.substr(0, pos); - return true; + size_t pos = in.rfind("."); + if (pos == string::npos) { + return false; + } + suffix = in.substr(pos + 1); + in = in.substr(0, pos); + return true; } /* Separate channel names as generated by Blender. @@ -87,39 +87,40 @@ static bool split_last_dot(string &in, string &suffix) * Inputs are expected in the form RenderLayer.Pass.View.Channel, sets renderlayer to "RenderLayer.View" * Otherwise: * Inputs are expected in the form RenderLayer.Pass.Channel */ -static bool parse_channel_name(string name, string &renderlayer, string &pass, string &channel, bool multiview_channels) +static bool parse_channel_name( + string name, string &renderlayer, string &pass, string &channel, bool multiview_channels) { - if(!split_last_dot(name, channel)) { - return false; - } - string view; - if(multiview_channels && !split_last_dot(name, view)) { - return false; - } - if(!split_last_dot(name, pass)) { - return false; - } - renderlayer = name; + if (!split_last_dot(name, channel)) { + return false; + } + string view; + if (multiview_channels && !split_last_dot(name, view)) { + return false; + } + if (!split_last_dot(name, pass)) { + return false; + } + renderlayer = name; - if(multiview_channels) { - renderlayer += "." + view; - } + if (multiview_channels) { + renderlayer += "." + view; + } - return true; + return true; } /* Channel Mapping */ struct ChannelMapping { - int channel; - string name; + int channel; + string name; }; static void fill_mapping(vector<ChannelMapping> &map, int pos, string name, string channels) { - for(const char *chan = channels.c_str(); *chan; chan++) { - map.push_back({pos++, name + "." + *chan}); - } + for (const char *chan = channels.c_str(); *chan; chan++) { + map.push_back({pos++, name + "." + *chan}); + } } static const int INPUT_NUM_CHANNELS = 15; @@ -132,131 +133,135 @@ static const int INPUT_DENOISING_VARIANCE = 11; static const int INPUT_DENOISING_INTENSITY = 14; static vector<ChannelMapping> input_channels() { - vector<ChannelMapping> map; - fill_mapping(map, INPUT_DENOISING_DEPTH, "Denoising Depth", "Z"); - fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ"); - fill_mapping(map, INPUT_DENOISING_SHADOWING, "Denoising Shadowing", "X"); - fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB"); - fill_mapping(map, INPUT_NOISY_IMAGE, "Noisy Image", "RGB"); - fill_mapping(map, INPUT_DENOISING_VARIANCE, "Denoising Variance", "RGB"); - fill_mapping(map, INPUT_DENOISING_INTENSITY, "Denoising Intensity", "X"); - return map; + vector<ChannelMapping> map; + fill_mapping(map, INPUT_DENOISING_DEPTH, "Denoising Depth", "Z"); + fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ"); + fill_mapping(map, INPUT_DENOISING_SHADOWING, "Denoising Shadowing", "X"); + fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB"); + fill_mapping(map, INPUT_NOISY_IMAGE, "Noisy Image", "RGB"); + fill_mapping(map, INPUT_DENOISING_VARIANCE, "Denoising Variance", "RGB"); + fill_mapping(map, INPUT_DENOISING_INTENSITY, "Denoising Intensity", "X"); + return map; } static const int OUTPUT_NUM_CHANNELS = 3; static vector<ChannelMapping> output_channels() { - vector<ChannelMapping> map; - fill_mapping(map, 0, "Combined", "RGB"); - return map; + vector<ChannelMapping> map; + fill_mapping(map, 0, "Combined", "RGB"); + return map; } /* Renderlayer Handling */ bool DenoiseImageLayer::detect_denoising_channels() { - /* Map device input to image channels. */ - input_to_image_channel.clear(); - input_to_image_channel.resize(INPUT_NUM_CHANNELS, -1); + /* Map device input to image channels. */ + input_to_image_channel.clear(); + input_to_image_channel.resize(INPUT_NUM_CHANNELS, -1); - foreach(const ChannelMapping& mapping, input_channels()) { - vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name); - if(i == channels.end()) { - return false; - } + foreach (const ChannelMapping &mapping, input_channels()) { + vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name); + if (i == channels.end()) { + return false; + } - size_t input_channel = mapping.channel; - size_t layer_channel = i - channels.begin(); - input_to_image_channel[input_channel] = layer_to_image_channel[layer_channel]; - } + size_t input_channel = mapping.channel; + size_t layer_channel = i - channels.begin(); + input_to_image_channel[input_channel] = layer_to_image_channel[layer_channel]; + } - /* Map device output to image channels. */ - output_to_image_channel.clear(); - output_to_image_channel.resize(OUTPUT_NUM_CHANNELS, -1); + /* Map device output to image channels. */ + output_to_image_channel.clear(); + output_to_image_channel.resize(OUTPUT_NUM_CHANNELS, -1); - foreach(const ChannelMapping& mapping, output_channels()) { - vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name); - if(i == channels.end()) { - return false; - } + foreach (const ChannelMapping &mapping, output_channels()) { + vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name); + if (i == channels.end()) { + return false; + } - size_t output_channel = mapping.channel; - size_t layer_channel = i - channels.begin(); - output_to_image_channel[output_channel] = layer_to_image_channel[layer_channel]; - } + size_t output_channel = mapping.channel; + size_t layer_channel = i - channels.begin(); + output_to_image_channel[output_channel] = layer_to_image_channel[layer_channel]; + } - /* Check that all buffer channels are correctly set. */ - for(int i = 0; i < INPUT_NUM_CHANNELS; i++) { - assert(input_to_image_channel[i] >= 0); - } - for(int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { - assert(output_to_image_channel[i] >= 0); - } + /* Check that all buffer channels are correctly set. */ + for (int i = 0; i < INPUT_NUM_CHANNELS; i++) { + assert(input_to_image_channel[i] >= 0); + } + for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { + assert(output_to_image_channel[i] >= 0); + } - return true; + return true; } bool DenoiseImageLayer::match_channels(int neighbor, const std::vector<string> &channelnames, const std::vector<string> &neighbor_channelnames) { - neighbor_input_to_image_channel.resize(neighbor + 1); - vector<int>& mapping = neighbor_input_to_image_channel[neighbor]; + neighbor_input_to_image_channel.resize(neighbor + 1); + vector<int> &mapping = neighbor_input_to_image_channel[neighbor]; - assert(mapping.size() == 0); - mapping.resize(input_to_image_channel.size(), -1); + assert(mapping.size() == 0); + mapping.resize(input_to_image_channel.size(), -1); - for(int i = 0; i < input_to_image_channel.size(); i++) { - const string& channel = channelnames[input_to_image_channel[i]]; - std::vector<string>::const_iterator frame_channel = find(neighbor_channelnames.begin(), neighbor_channelnames.end(), channel); + for (int i = 0; i < input_to_image_channel.size(); i++) { + const string &channel = channelnames[input_to_image_channel[i]]; + std::vector<string>::const_iterator frame_channel = find( + neighbor_channelnames.begin(), neighbor_channelnames.end(), channel); - if(frame_channel == neighbor_channelnames.end()) { - return false; - } + if (frame_channel == neighbor_channelnames.end()) { + return false; + } - mapping[i] = frame_channel - neighbor_channelnames.begin(); - } + mapping[i] = frame_channel - neighbor_channelnames.begin(); + } - return true; + return true; } /* Denoise Task */ -DenoiseTask::DenoiseTask(Device *device, Denoiser *denoiser, int frame, const vector<int>& neighbor_frames) -: denoiser(denoiser), - device(device), - frame(frame), - neighbor_frames(neighbor_frames), - current_layer(0), - input_pixels(device, "filter input buffer", MEM_READ_ONLY), - num_tiles(0) +DenoiseTask::DenoiseTask(Device *device, + Denoiser *denoiser, + int frame, + const vector<int> &neighbor_frames) + : denoiser(denoiser), + device(device), + frame(frame), + neighbor_frames(neighbor_frames), + current_layer(0), + input_pixels(device, "filter input buffer", MEM_READ_ONLY), + num_tiles(0) { - image.samples = denoiser->samples_override; + image.samples = denoiser->samples_override; } DenoiseTask::~DenoiseTask() { - free(); + free(); } /* Device callbacks */ bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile &tile) { - thread_scoped_lock tile_lock(tiles_mutex); + thread_scoped_lock tile_lock(tiles_mutex); - if(tiles.empty()) { - return false; - } + if (tiles.empty()) { + return false; + } - tile = tiles.front(); - tiles.pop_front(); + tile = tiles.front(); + tiles.pop_front(); - device->map_tile(tile_device, tile); + device->map_tile(tile_device, tile); - print_progress(num_tiles - tiles.size(), num_tiles, frame, denoiser->num_frames); + print_progress(num_tiles - tiles.size(), num_tiles, frame, denoiser->num_frames); - return true; + return true; } /* Mapping tiles is required for regular rendering since each tile has its separate memory @@ -268,87 +273,89 @@ bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile & * a different buffer to avoid having to copy an entire horizontal slice of the image. */ void DenoiseTask::map_neighboring_tiles(RenderTile *tiles, Device *tile_device) { - /* Fill tile information. */ - for(int i = 0; i < 9; i++) { - if(i == 4) { - continue; - } - - int dx = (i%3)-1; - int dy = (i/3)-1; - tiles[i].x = clamp(tiles[4].x + dx *denoiser->tile_size.x, 0, image.width); - tiles[i].w = clamp(tiles[4].x + (dx+1)*denoiser->tile_size.x, 0, image.width) - tiles[i].x; - tiles[i].y = clamp(tiles[4].y + dy *denoiser->tile_size.y, 0, image.height); - tiles[i].h = clamp(tiles[4].y + (dy+1)*denoiser->tile_size.y, 0, image.height) - tiles[i].y; - - tiles[i].buffer = tiles[4].buffer; - tiles[i].offset = tiles[4].offset; - tiles[i].stride = image.width; - } - - /* Allocate output buffer. */ - device_vector<float> *output_mem = new device_vector<float>(tile_device, "denoising_output", MEM_READ_WRITE); - output_mem->alloc(OUTPUT_NUM_CHANNELS*tiles[4].w*tiles[4].h); - - /* Fill output buffer with noisy image, assumed by kernel_filter_finalize - * when skipping denoising of some pixels. */ - float *result = output_mem->data(); - float *in = &image.pixels[image.num_channels*(tiles[4].y*image.width + tiles[4].x)]; - - const DenoiseImageLayer& layer = image.layers[current_layer]; - const int *input_to_image_channel = layer.input_to_image_channel.data(); - - for(int y = 0; y < tiles[4].h; y++) { - for(int x = 0; x < tiles[4].w; x++, result += OUTPUT_NUM_CHANNELS) { - for(int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { - result[i] = in[image.num_channels*x + input_to_image_channel[INPUT_NOISY_IMAGE + i]]; - } - } - in += image.num_channels * image.width; - } - - output_mem->copy_to_device(); - - /* Fill output tile info. */ - tiles[9] = tiles[4]; - tiles[9].buffer = output_mem->device_pointer; - tiles[9].stride = tiles[9].w; - tiles[9].offset -= tiles[9].x + tiles[9].y*tiles[9].stride; - - thread_scoped_lock output_lock(output_mutex); - assert(output_pixels.count(tiles[4].tile_index) == 0); - output_pixels[tiles[9].tile_index] = output_mem; + /* Fill tile information. */ + for (int i = 0; i < 9; i++) { + if (i == 4) { + continue; + } + + int dx = (i % 3) - 1; + int dy = (i / 3) - 1; + tiles[i].x = clamp(tiles[4].x + dx * denoiser->tile_size.x, 0, image.width); + tiles[i].w = clamp(tiles[4].x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tiles[i].x; + tiles[i].y = clamp(tiles[4].y + dy * denoiser->tile_size.y, 0, image.height); + tiles[i].h = clamp(tiles[4].y + (dy + 1) * denoiser->tile_size.y, 0, image.height) - + tiles[i].y; + + tiles[i].buffer = tiles[4].buffer; + tiles[i].offset = tiles[4].offset; + tiles[i].stride = image.width; + } + + /* Allocate output buffer. */ + device_vector<float> *output_mem = new device_vector<float>( + tile_device, "denoising_output", MEM_READ_WRITE); + output_mem->alloc(OUTPUT_NUM_CHANNELS * tiles[4].w * tiles[4].h); + + /* Fill output buffer with noisy image, assumed by kernel_filter_finalize + * when skipping denoising of some pixels. */ + float *result = output_mem->data(); + float *in = &image.pixels[image.num_channels * (tiles[4].y * image.width + tiles[4].x)]; + + const DenoiseImageLayer &layer = image.layers[current_layer]; + const int *input_to_image_channel = layer.input_to_image_channel.data(); + + for (int y = 0; y < tiles[4].h; y++) { + for (int x = 0; x < tiles[4].w; x++, result += OUTPUT_NUM_CHANNELS) { + for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { + result[i] = in[image.num_channels * x + input_to_image_channel[INPUT_NOISY_IMAGE + i]]; + } + } + in += image.num_channels * image.width; + } + + output_mem->copy_to_device(); + + /* Fill output tile info. */ + tiles[9] = tiles[4]; + tiles[9].buffer = output_mem->device_pointer; + tiles[9].stride = tiles[9].w; + tiles[9].offset -= tiles[9].x + tiles[9].y * tiles[9].stride; + + thread_scoped_lock output_lock(output_mutex); + assert(output_pixels.count(tiles[4].tile_index) == 0); + output_pixels[tiles[9].tile_index] = output_mem; } void DenoiseTask::unmap_neighboring_tiles(RenderTile *tiles) { - thread_scoped_lock output_lock(output_mutex); - assert(output_pixels.count(tiles[4].tile_index) == 1); - device_vector<float> *output_mem = output_pixels[tiles[9].tile_index]; - output_pixels.erase(tiles[4].tile_index); - output_lock.unlock(); + thread_scoped_lock output_lock(output_mutex); + assert(output_pixels.count(tiles[4].tile_index) == 1); + device_vector<float> *output_mem = output_pixels[tiles[9].tile_index]; + output_pixels.erase(tiles[4].tile_index); + output_lock.unlock(); - /* Copy denoised pixels from device. */ - output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS*tiles[9].w, tiles[9].h); + /* Copy denoised pixels from device. */ + output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * tiles[9].w, tiles[9].h); - float *result = output_mem->data(); - float *out = &image.pixels[image.num_channels*(tiles[9].y*image.width + tiles[9].x)]; + float *result = output_mem->data(); + float *out = &image.pixels[image.num_channels * (tiles[9].y * image.width + tiles[9].x)]; - const DenoiseImageLayer& layer = image.layers[current_layer]; - const int *output_to_image_channel = layer.output_to_image_channel.data(); + const DenoiseImageLayer &layer = image.layers[current_layer]; + const int *output_to_image_channel = layer.output_to_image_channel.data(); - for(int y = 0; y < tiles[9].h; y++) { - for(int x = 0; x < tiles[9].w; x++, result += OUTPUT_NUM_CHANNELS) { - for(int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { - out[image.num_channels*x + output_to_image_channel[i]] = result[i]; - } - } - out += image.num_channels * image.width; - } + for (int y = 0; y < tiles[9].h; y++) { + for (int x = 0; x < tiles[9].w; x++, result += OUTPUT_NUM_CHANNELS) { + for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { + out[image.num_channels * x + output_to_image_channel[i]] = result[i]; + } + } + out += image.num_channels * image.width; + } - /* Free device buffer. */ - output_mem->free(); - delete output_mem; + /* Free device buffer. */ + output_mem->free(); + delete output_mem; } void DenoiseTask::release_tile() @@ -357,542 +364,547 @@ void DenoiseTask::release_tile() bool DenoiseTask::get_cancel() { - return false; -} - -void DenoiseTask::create_task(DeviceTask& task) -{ - /* Callback functions. */ - task.acquire_tile = function_bind(&DenoiseTask::acquire_tile, this, device, _1, _2); - task.map_neighbor_tiles = function_bind(&DenoiseTask::map_neighboring_tiles, this, _1, _2); - task.unmap_neighbor_tiles = function_bind(&DenoiseTask::unmap_neighboring_tiles, this, _1); - task.release_tile = function_bind(&DenoiseTask::release_tile, this); - task.get_cancel = function_bind(&DenoiseTask::get_cancel, this); - - /* Denoising parameters. */ - task.denoising = denoiser->params; - task.denoising_do_filter = true; - task.denoising_write_passes = false; - task.denoising_from_render = false; - - task.denoising_frames.resize(neighbor_frames.size()); - for(int i = 0; i < neighbor_frames.size(); i++) { - task.denoising_frames[i] = neighbor_frames[i] - frame; - } - - /* Buffer parameters. */ - task.pass_stride = INPUT_NUM_CHANNELS; - task.target_pass_stride = OUTPUT_NUM_CHANNELS; - task.pass_denoising_data = 0; - task.pass_denoising_clean = -1; - task.frame_stride = image.width * image.height * INPUT_NUM_CHANNELS; - - /* Create tiles. */ - thread_scoped_lock tile_lock(tiles_mutex); - thread_scoped_lock output_lock(output_mutex); - - tiles.clear(); - assert(output_pixels.empty()); - output_pixels.clear(); - - int tiles_x = divide_up(image.width, denoiser->tile_size.x); - int tiles_y = divide_up(image.height, denoiser->tile_size.y); - - for(int ty = 0; ty < tiles_y; ty++) { - for(int tx = 0; tx < tiles_x; tx++) { - RenderTile tile; - tile.x = tx * denoiser->tile_size.x; - tile.y = ty * denoiser->tile_size.y; - tile.w = min(image.width - tile.x, denoiser->tile_size.x); - tile.h = min(image.height - tile.y, denoiser->tile_size.y); - tile.start_sample = 0; - tile.num_samples = image.layers[current_layer].samples; - tile.sample = 0; - tile.offset = 0; - tile.stride = image.width; - tile.tile_index = ty*tiles_x + tx; - tile.task = RenderTile::DENOISE; - tile.buffers = NULL; - tile.buffer = input_pixels.device_pointer; - tiles.push_back(tile); - } - } - - num_tiles = tiles.size(); + return false; +} + +void DenoiseTask::create_task(DeviceTask &task) +{ + /* Callback functions. */ + task.acquire_tile = function_bind(&DenoiseTask::acquire_tile, this, device, _1, _2); + task.map_neighbor_tiles = function_bind(&DenoiseTask::map_neighboring_tiles, this, _1, _2); + task.unmap_neighbor_tiles = function_bind(&DenoiseTask::unmap_neighboring_tiles, this, _1); + task.release_tile = function_bind(&DenoiseTask::release_tile, this); + task.get_cancel = function_bind(&DenoiseTask::get_cancel, this); + + /* Denoising parameters. */ + task.denoising = denoiser->params; + task.denoising_do_filter = true; + task.denoising_write_passes = false; + task.denoising_from_render = false; + + task.denoising_frames.resize(neighbor_frames.size()); + for (int i = 0; i < neighbor_frames.size(); i++) { + task.denoising_frames[i] = neighbor_frames[i] - frame; + } + + /* Buffer parameters. */ + task.pass_stride = INPUT_NUM_CHANNELS; + task.target_pass_stride = OUTPUT_NUM_CHANNELS; + task.pass_denoising_data = 0; + task.pass_denoising_clean = -1; + task.frame_stride = image.width * image.height * INPUT_NUM_CHANNELS; + + /* Create tiles. */ + thread_scoped_lock tile_lock(tiles_mutex); + thread_scoped_lock output_lock(output_mutex); + + tiles.clear(); + assert(output_pixels.empty()); + output_pixels.clear(); + + int tiles_x = divide_up(image.width, denoiser->tile_size.x); + int tiles_y = divide_up(image.height, denoiser->tile_size.y); + + for (int ty = 0; ty < tiles_y; ty++) { + for (int tx = 0; tx < tiles_x; tx++) { + RenderTile tile; + tile.x = tx * denoiser->tile_size.x; + tile.y = ty * denoiser->tile_size.y; + tile.w = min(image.width - tile.x, denoiser->tile_size.x); + tile.h = min(image.height - tile.y, denoiser->tile_size.y); + tile.start_sample = 0; + tile.num_samples = image.layers[current_layer].samples; + tile.sample = 0; + tile.offset = 0; + tile.stride = image.width; + tile.tile_index = ty * tiles_x + tx; + tile.task = RenderTile::DENOISE; + tile.buffers = NULL; + tile.buffer = input_pixels.device_pointer; + tiles.push_back(tile); + } + } + + num_tiles = tiles.size(); } /* Denoiser Operations */ bool DenoiseTask::load_input_pixels(int layer) { - int w = image.width; - int h = image.height; - int num_pixels = image.width * image.height; - int frame_stride = num_pixels * INPUT_NUM_CHANNELS; - - /* Load center image */ - DenoiseImageLayer& image_layer = image.layers[layer]; - - float *buffer_data = input_pixels.data(); - image.read_pixels(image_layer, buffer_data); - buffer_data += frame_stride; - - /* Load neighbor images */ - for(int i = 0; i < image.in_neighbors.size(); i++) { - if(!image.read_neighbor_pixels(i, image_layer, buffer_data)) { - error = "Failed to read neighbor frame pixels"; - return false; - } - buffer_data += frame_stride; - } - - /* Preprocess */ - buffer_data = input_pixels.data(); - for(int neighbor = 0; neighbor < image.in_neighbors.size() + 1; neighbor++) { - /* Clamp */ - if(denoiser->params.clamp_input) { - for(int i = 0; i < num_pixels*INPUT_NUM_CHANNELS; i++) { - buffer_data[i] = clamp(buffer_data[i], -1e8f, 1e8f); - } - } - - /* Box blur */ - int r = 5 * denoiser->params.radius; - float *data = buffer_data + 14; - array<float> temp(num_pixels); - - for(int y = 0; y < h; y++) { - for(int x = 0; x < w; x++) { - int n = 0; - float sum = 0.0f; - for(int dx = max(x - r, 0); dx < min(x + r + 1, w); dx++, n++) { - sum += data[INPUT_NUM_CHANNELS * (y * w + dx)]; - } - temp[y * w + x] = sum/n; - } - } - - for(int y = 0; y < h; y++) { - for(int x = 0; x < w; x++) { - int n = 0; - float sum = 0.0f; - - for(int dy = max(y - r, 0); dy < min(y + r + 1, h); dy++, n++) { - sum += temp[dy * w + x]; - } - - data[INPUT_NUM_CHANNELS * (y * w + x)] = sum/n; - } - } - - buffer_data += frame_stride; - } - - /* Copy to device */ - input_pixels.copy_to_device(); - - return true; + int w = image.width; + int h = image.height; + int num_pixels = image.width * image.height; + int frame_stride = num_pixels * INPUT_NUM_CHANNELS; + + /* Load center image */ + DenoiseImageLayer &image_layer = image.layers[layer]; + + float *buffer_data = input_pixels.data(); + image.read_pixels(image_layer, buffer_data); + buffer_data += frame_stride; + + /* Load neighbor images */ + for (int i = 0; i < image.in_neighbors.size(); i++) { + if (!image.read_neighbor_pixels(i, image_layer, buffer_data)) { + error = "Failed to read neighbor frame pixels"; + return false; + } + buffer_data += frame_stride; + } + + /* Preprocess */ + buffer_data = input_pixels.data(); + for (int neighbor = 0; neighbor < image.in_neighbors.size() + 1; neighbor++) { + /* Clamp */ + if (denoiser->params.clamp_input) { + for (int i = 0; i < num_pixels * INPUT_NUM_CHANNELS; i++) { + buffer_data[i] = clamp(buffer_data[i], -1e8f, 1e8f); + } + } + + /* Box blur */ + int r = 5 * denoiser->params.radius; + float *data = buffer_data + 14; + array<float> temp(num_pixels); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int n = 0; + float sum = 0.0f; + for (int dx = max(x - r, 0); dx < min(x + r + 1, w); dx++, n++) { + sum += data[INPUT_NUM_CHANNELS * (y * w + dx)]; + } + temp[y * w + x] = sum / n; + } + } + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int n = 0; + float sum = 0.0f; + + for (int dy = max(y - r, 0); dy < min(y + r + 1, h); dy++, n++) { + sum += temp[dy * w + x]; + } + + data[INPUT_NUM_CHANNELS * (y * w + x)] = sum / n; + } + } + + buffer_data += frame_stride; + } + + /* Copy to device */ + input_pixels.copy_to_device(); + + return true; } /* Task stages */ bool DenoiseTask::load() { - string center_filepath = denoiser->input[frame]; - if(!image.load(center_filepath, error)) { - return false; - } + string center_filepath = denoiser->input[frame]; + if (!image.load(center_filepath, error)) { + return false; + } - if(!image.load_neighbors(denoiser->input, neighbor_frames, error)) { - return false; - } + if (!image.load_neighbors(denoiser->input, neighbor_frames, error)) { + return false; + } - if(image.layers.empty()) { - error = "No image layers found to denoise in " + center_filepath; - return false; - } + if (image.layers.empty()) { + error = "No image layers found to denoise in " + center_filepath; + return false; + } - /* Allocate device buffer. */ - int num_frames = image.in_neighbors.size() + 1; - input_pixels.alloc(image.width * INPUT_NUM_CHANNELS, image.height * num_frames); - input_pixels.zero_to_device(); + /* Allocate device buffer. */ + int num_frames = image.in_neighbors.size() + 1; + input_pixels.alloc(image.width * INPUT_NUM_CHANNELS, image.height * num_frames); + input_pixels.zero_to_device(); - /* Read pixels for first layer. */ - current_layer = 0; - if(!load_input_pixels(current_layer)) { - return false; - } + /* Read pixels for first layer. */ + current_layer = 0; + if (!load_input_pixels(current_layer)) { + return false; + } - return true; + return true; } bool DenoiseTask::exec() { - for(current_layer = 0; current_layer < image.layers.size(); current_layer++) { - /* Read pixels for secondary layers, first was already loaded. */ - if(current_layer > 0) { - if(!load_input_pixels(current_layer)) { - return false; - } - } + for (current_layer = 0; current_layer < image.layers.size(); current_layer++) { + /* Read pixels for secondary layers, first was already loaded. */ + if (current_layer > 0) { + if (!load_input_pixels(current_layer)) { + return false; + } + } - /* Run task on device. */ - DeviceTask task(DeviceTask::RENDER); - create_task(task); - device->task_add(task); - device->task_wait(); + /* Run task on device. */ + DeviceTask task(DeviceTask::RENDER); + create_task(task); + device->task_add(task); + device->task_wait(); - printf("\n"); - } + printf("\n"); + } - return true; + return true; } bool DenoiseTask::save() { - bool ok = image.save_output(denoiser->output[frame], error); - free(); - return ok; + bool ok = image.save_output(denoiser->output[frame], error); + free(); + return ok; } void DenoiseTask::free() { - image.free(); - input_pixels.free(); - assert(output_pixels.empty()); + image.free(); + input_pixels.free(); + assert(output_pixels.empty()); } /* Denoise Image Storage */ DenoiseImage::DenoiseImage() { - width = 0; - height = 0; - num_channels = 0; - samples = 0; + width = 0; + height = 0; + num_channels = 0; + samples = 0; } DenoiseImage::~DenoiseImage() { - free(); + free(); } void DenoiseImage::close_input() { - in_neighbors.clear(); + in_neighbors.clear(); } void DenoiseImage::free() { - close_input(); - pixels.clear(); -} - -bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string& error) + close_input(); + pixels.clear(); +} + +bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string &error) { - const std::vector<string> &channels = in_spec.channelnames; - const ParamValue *multiview = in_spec.find_attribute("multiView"); - const bool multiview_channels = (multiview && - multiview->type().basetype == TypeDesc::STRING && - multiview->type().arraylen >= 2); - - layers.clear(); - - /* Loop over all the channels in the file, parse their name and sort them - * by RenderLayer. - * Channels that can't be parsed are directly passed through to the output. */ - map<string, DenoiseImageLayer> file_layers; - for(int i = 0; i < channels.size(); i++) { - string layer, pass, channel; - if(parse_channel_name(channels[i], layer, pass, channel, multiview_channels)) { - file_layers[layer].channels.push_back(pass + "." + channel); - file_layers[layer].layer_to_image_channel.push_back(i); - } - } - - /* Loop over all detected RenderLayers, check whether they contain a full set of input channels. - * Any channels that won't be processed internally are also passed through. */ - for(map<string, DenoiseImageLayer>::iterator i = file_layers.begin(); i != file_layers.end(); ++i) { - const string& name = i->first; - DenoiseImageLayer& layer = i->second; - - /* Check for full pass set. */ - if(!layer.detect_denoising_channels()) { - continue; - } - - layer.name = name; - layer.samples = samples; - - /* If the sample value isn't set yet, check if there is a layer-specific one in the input file. */ - if(layer.samples < 1) { - string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", ""); - if(sample_string != "") { - if(!sscanf(sample_string.c_str(), "%d", &layer.samples)) { - error = "Failed to parse samples metadata: " + sample_string; - return false; - } - } - } - - if(layer.samples < 1) { - error = string_printf("No sample number specified in the file for layer %s or on the command line", name.c_str()); - return false; - } - - layers.push_back(layer); - } - - return true; -} - -void DenoiseImage::read_pixels(const DenoiseImageLayer& layer, float *input_pixels) -{ - /* Pixels from center file have already been loaded into pixels. - * We copy a subset into the device input buffer with channels reshuffled. */ - const int *input_to_image_channel = layer.input_to_image_channel.data(); - - for(int i = 0; i < width * height; i++) { - for(int j = 0; j < INPUT_NUM_CHANNELS; j++) { - int image_channel = input_to_image_channel[j]; - input_pixels[i*INPUT_NUM_CHANNELS + j] = pixels[((size_t)i)*num_channels + image_channel]; - } - } -} - -bool DenoiseImage::read_neighbor_pixels(int neighbor, const DenoiseImageLayer& layer, float *input_pixels) -{ - /* Load pixels from neighboring frames, and copy them into device buffer - * with channels reshuffled. */ - size_t num_pixels = (size_t)width * (size_t)height; - array<float> neighbor_pixels(num_pixels * num_channels); - if(!in_neighbors[neighbor]->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) { - return false; - } - - const int *input_to_image_channel = layer.neighbor_input_to_image_channel[neighbor].data(); - - for(int i = 0; i < width * height; i++) { - for(int j = 0; j < INPUT_NUM_CHANNELS; j++) { - int image_channel = input_to_image_channel[j]; - input_pixels[i*INPUT_NUM_CHANNELS + j] = neighbor_pixels[((size_t)i)*num_channels + image_channel]; - } - } - - return true; -} - -bool DenoiseImage::load(const string& in_filepath, string& error) -{ - if(!Filesystem::is_regular(in_filepath)) { - error = "Couldn't find file: " + in_filepath; - return false; - } - - unique_ptr<ImageInput> in(ImageInput::open(in_filepath)); - if(!in) { - error = "Couldn't open file: " + in_filepath; - return false; - } - - in_spec = in->spec(); - width = in_spec.width; - height = in_spec.height; - num_channels = in_spec.nchannels; - - if(!parse_channels(in_spec, error)) { - return false; - } - - if(layers.size() == 0) { - error = "Could not find a render layer containing denoising info"; - return false; - } - - size_t num_pixels = (size_t)width * (size_t)height; - pixels.resize(num_pixels * num_channels); - - /* Read all channels into buffer. Reading all channels at once is faster - * than individually due to interleaved EXR channel storage. */ - if(!in->read_image(TypeDesc::FLOAT, pixels.data())) { - error = "Failed to read image: " + in_filepath; - return false; - } - - return true; -} - -bool DenoiseImage::load_neighbors(const vector<string>& filepaths, const vector<int>& frames, string& error) -{ - if(frames.size() > DENOISE_MAX_FRAMES - 1) { - error = string_printf("Maximum number of neighbors (%d) exceeded\n", DENOISE_MAX_FRAMES - 1); - return false; - } - - for(int neighbor = 0; neighbor < frames.size(); neighbor++) { - int frame = frames[neighbor]; - const string& filepath = filepaths[frame]; - - if(!Filesystem::is_regular(filepath)) { - error = "Couldn't find neighbor frame: " + filepath; - return false; - } - - unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath)); - if(!in_neighbor) { - error = "Couldn't open neighbor frame: " + filepath; - return false; - } + const std::vector<string> &channels = in_spec.channelnames; + const ParamValue *multiview = in_spec.find_attribute("multiView"); + const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING && + multiview->type().arraylen >= 2); + + layers.clear(); + + /* Loop over all the channels in the file, parse their name and sort them + * by RenderLayer. + * Channels that can't be parsed are directly passed through to the output. */ + map<string, DenoiseImageLayer> file_layers; + for (int i = 0; i < channels.size(); i++) { + string layer, pass, channel; + if (parse_channel_name(channels[i], layer, pass, channel, multiview_channels)) { + file_layers[layer].channels.push_back(pass + "." + channel); + file_layers[layer].layer_to_image_channel.push_back(i); + } + } + + /* Loop over all detected RenderLayers, check whether they contain a full set of input channels. + * Any channels that won't be processed internally are also passed through. */ + for (map<string, DenoiseImageLayer>::iterator i = file_layers.begin(); i != file_layers.end(); + ++i) { + const string &name = i->first; + DenoiseImageLayer &layer = i->second; + + /* Check for full pass set. */ + if (!layer.detect_denoising_channels()) { + continue; + } + + layer.name = name; + layer.samples = samples; + + /* If the sample value isn't set yet, check if there is a layer-specific one in the input file. */ + if (layer.samples < 1) { + string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", ""); + if (sample_string != "") { + if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) { + error = "Failed to parse samples metadata: " + sample_string; + return false; + } + } + } + + if (layer.samples < 1) { + error = string_printf( + "No sample number specified in the file for layer %s or on the command line", + name.c_str()); + return false; + } + + layers.push_back(layer); + } + + return true; +} + +void DenoiseImage::read_pixels(const DenoiseImageLayer &layer, float *input_pixels) +{ + /* Pixels from center file have already been loaded into pixels. + * We copy a subset into the device input buffer with channels reshuffled. */ + const int *input_to_image_channel = layer.input_to_image_channel.data(); + + for (int i = 0; i < width * height; i++) { + for (int j = 0; j < INPUT_NUM_CHANNELS; j++) { + int image_channel = input_to_image_channel[j]; + input_pixels[i * INPUT_NUM_CHANNELS + j] = + pixels[((size_t)i) * num_channels + image_channel]; + } + } +} + +bool DenoiseImage::read_neighbor_pixels(int neighbor, + const DenoiseImageLayer &layer, + float *input_pixels) +{ + /* Load pixels from neighboring frames, and copy them into device buffer + * with channels reshuffled. */ + size_t num_pixels = (size_t)width * (size_t)height; + array<float> neighbor_pixels(num_pixels * num_channels); + if (!in_neighbors[neighbor]->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) { + return false; + } + + const int *input_to_image_channel = layer.neighbor_input_to_image_channel[neighbor].data(); + + for (int i = 0; i < width * height; i++) { + for (int j = 0; j < INPUT_NUM_CHANNELS; j++) { + int image_channel = input_to_image_channel[j]; + input_pixels[i * INPUT_NUM_CHANNELS + j] = + neighbor_pixels[((size_t)i) * num_channels + image_channel]; + } + } + + return true; +} + +bool DenoiseImage::load(const string &in_filepath, string &error) +{ + if (!Filesystem::is_regular(in_filepath)) { + error = "Couldn't find file: " + in_filepath; + return false; + } + + unique_ptr<ImageInput> in(ImageInput::open(in_filepath)); + if (!in) { + error = "Couldn't open file: " + in_filepath; + return false; + } + + in_spec = in->spec(); + width = in_spec.width; + height = in_spec.height; + num_channels = in_spec.nchannels; + + if (!parse_channels(in_spec, error)) { + return false; + } + + if (layers.size() == 0) { + error = "Could not find a render layer containing denoising info"; + return false; + } + + size_t num_pixels = (size_t)width * (size_t)height; + pixels.resize(num_pixels * num_channels); + + /* Read all channels into buffer. Reading all channels at once is faster + * than individually due to interleaved EXR channel storage. */ + if (!in->read_image(TypeDesc::FLOAT, pixels.data())) { + error = "Failed to read image: " + in_filepath; + return false; + } + + return true; +} + +bool DenoiseImage::load_neighbors(const vector<string> &filepaths, + const vector<int> &frames, + string &error) +{ + if (frames.size() > DENOISE_MAX_FRAMES - 1) { + error = string_printf("Maximum number of neighbors (%d) exceeded\n", DENOISE_MAX_FRAMES - 1); + return false; + } + + for (int neighbor = 0; neighbor < frames.size(); neighbor++) { + int frame = frames[neighbor]; + const string &filepath = filepaths[frame]; - const ImageSpec &neighbor_spec = in_neighbor->spec(); - if(neighbor_spec.width != width || neighbor_spec.height != height) { - error = "Neighbor frame has different dimensions: " + filepath; - return false; - } - - foreach(DenoiseImageLayer& layer, layers) { - if(!layer.match_channels(neighbor, - in_spec.channelnames, - neighbor_spec.channelnames)) - { - error = "Neighbor frame misses denoising data passes: " + filepath; - return false; - } - } - - in_neighbors.push_back(std::move(in_neighbor)); - } - - return true; -} - -bool DenoiseImage::save_output(const string& out_filepath, string& error) -{ - /* Save image with identical dimensions, channels and metadata. */ - ImageSpec out_spec = in_spec; - - /* Ensure that the output frame contains sample information even if the input didn't. */ - for(int i = 0; i < layers.size(); i++) { - string name = "cycles." + layers[i].name + ".samples"; - if(!out_spec.find_attribute(name, TypeDesc::STRING)) { - out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", layers[i].samples)); - } - } + if (!Filesystem::is_regular(filepath)) { + error = "Couldn't find neighbor frame: " + filepath; + return false; + } + + unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath)); + if (!in_neighbor) { + error = "Couldn't open neighbor frame: " + filepath; + return false; + } + + const ImageSpec &neighbor_spec = in_neighbor->spec(); + if (neighbor_spec.width != width || neighbor_spec.height != height) { + error = "Neighbor frame has different dimensions: " + filepath; + return false; + } + + foreach (DenoiseImageLayer &layer, layers) { + if (!layer.match_channels(neighbor, in_spec.channelnames, neighbor_spec.channelnames)) { + error = "Neighbor frame misses denoising data passes: " + filepath; + return false; + } + } + + in_neighbors.push_back(std::move(in_neighbor)); + } + + return true; +} + +bool DenoiseImage::save_output(const string &out_filepath, string &error) +{ + /* Save image with identical dimensions, channels and metadata. */ + ImageSpec out_spec = in_spec; + + /* Ensure that the output frame contains sample information even if the input didn't. */ + for (int i = 0; i < layers.size(); i++) { + string name = "cycles." + layers[i].name + ".samples"; + if (!out_spec.find_attribute(name, TypeDesc::STRING)) { + out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", layers[i].samples)); + } + } - /* We don't need input anymore at this point, and will possibly - * overwrite the same file. */ - close_input(); - - /* Write to temporary file path, so we denoise images in place and don't - * risk destroying files when something goes wrong in file saving. */ - string extension = OIIO::Filesystem::extension(out_filepath); - string unique_name = ".denoise-tmp-" + OIIO::Filesystem::unique_path(); - string tmp_filepath = out_filepath + unique_name + extension; - unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath)); - - if(!out) { - error = "Failed to open temporary file " + tmp_filepath + " for writing"; - return false; - } - - /* Open temporary file and write image buffers. */ - if(!out->open(tmp_filepath, out_spec)) { - error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror(); - return false; - } - - bool ok = true; - if(!out->write_image(TypeDesc::FLOAT, pixels.data())) { - error = "Failed to write to file " + tmp_filepath + ": " + out->geterror(); - ok = false; - } - - if(!out->close()) { - error = "Failed to save to file " + tmp_filepath + ": " + out->geterror(); - ok = false; - } - - out.reset(); - - /* Copy temporary file to outputput filepath. */ - string rename_error; - if(ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) { - error = "Failed to move denoised image to " + out_filepath + ": " + rename_error; - ok = false; - } - - if(!ok) { - OIIO::Filesystem::remove(tmp_filepath); - } - - return ok; + /* We don't need input anymore at this point, and will possibly + * overwrite the same file. */ + close_input(); + + /* Write to temporary file path, so we denoise images in place and don't + * risk destroying files when something goes wrong in file saving. */ + string extension = OIIO::Filesystem::extension(out_filepath); + string unique_name = ".denoise-tmp-" + OIIO::Filesystem::unique_path(); + string tmp_filepath = out_filepath + unique_name + extension; + unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath)); + + if (!out) { + error = "Failed to open temporary file " + tmp_filepath + " for writing"; + return false; + } + + /* Open temporary file and write image buffers. */ + if (!out->open(tmp_filepath, out_spec)) { + error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror(); + return false; + } + + bool ok = true; + if (!out->write_image(TypeDesc::FLOAT, pixels.data())) { + error = "Failed to write to file " + tmp_filepath + ": " + out->geterror(); + ok = false; + } + + if (!out->close()) { + error = "Failed to save to file " + tmp_filepath + ": " + out->geterror(); + ok = false; + } + + out.reset(); + + /* Copy temporary file to outputput filepath. */ + string rename_error; + if (ok && !OIIO::Filesystem::rename(tmp_filepath, out_filepath, rename_error)) { + error = "Failed to move denoised image to " + out_filepath + ": " + rename_error; + ok = false; + } + + if (!ok) { + OIIO::Filesystem::remove(tmp_filepath); + } + + return ok; } /* File pattern handling and outer loop over frames */ -Denoiser::Denoiser(DeviceInfo& device_info) +Denoiser::Denoiser(DeviceInfo &device_info) { - samples_override = 0; - tile_size = make_int2(64, 64); + samples_override = 0; + tile_size = make_int2(64, 64); - num_frames = 0; + num_frames = 0; - /* Initialize task scheduler. */ - TaskScheduler::init(); + /* Initialize task scheduler. */ + TaskScheduler::init(); - /* Initialize device. */ - DeviceRequestedFeatures req; - device = Device::create(device_info, stats, profiler, true); - device->load_kernels(req); + /* Initialize device. */ + DeviceRequestedFeatures req; + device = Device::create(device_info, stats, profiler, true); + device->load_kernels(req); } Denoiser::~Denoiser() { - delete device; - TaskScheduler::exit(); + delete device; + TaskScheduler::exit(); } bool Denoiser::run() { - assert(input.size() == output.size()); - - num_frames = output.size(); - - for(int frame = 0; frame < num_frames; frame++) { - /* Skip empty output paths. */ - if(output[frame].empty()) { - continue; - } - - /* Determine neighbor frame numbers that should be used for filtering. */ - vector<int> neighbor_frames; - for(int f = frame - params.neighbor_frames; f <= frame + params.neighbor_frames; f++) { - if (f >= 0 && f < num_frames && f != frame) { - neighbor_frames.push_back(f); - } - } - - /* Execute task. */ - DenoiseTask task(device, this, frame, neighbor_frames); - if(!task.load()) { - error = task.error; - return false; - } - - if(!task.exec()) { - error = task.error; - return false; - } - - if(!task.save()) { - error = task.error; - return false; - } - - task.free(); - } - - return true; + assert(input.size() == output.size()); + + num_frames = output.size(); + + for (int frame = 0; frame < num_frames; frame++) { + /* Skip empty output paths. */ + if (output[frame].empty()) { + continue; + } + + /* Determine neighbor frame numbers that should be used for filtering. */ + vector<int> neighbor_frames; + for (int f = frame - params.neighbor_frames; f <= frame + params.neighbor_frames; f++) { + if (f >= 0 && f < num_frames && f != frame) { + neighbor_frames.push_back(f); + } + } + + /* Execute task. */ + DenoiseTask task(device, this, frame, neighbor_frames); + if (!task.load()) { + error = task.error; + return false; + } + + if (!task.exec()) { + error = task.error; + return false; + } + + if (!task.save()) { + error = task.error; + return false; + } + + task.free(); + } + + return true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/denoising.h b/intern/cycles/render/denoising.h index 5bf1a8dd0fa..dcb842a4603 100644 --- a/intern/cycles/render/denoising.h +++ b/intern/cycles/render/denoising.h @@ -35,166 +35,166 @@ CCL_NAMESPACE_BEGIN /* Denoiser */ class Denoiser { -public: - Denoiser(DeviceInfo& device_info); - ~Denoiser(); + public: + Denoiser(DeviceInfo &device_info); + ~Denoiser(); - bool run(); + bool run(); - /* Error message after running, in case of failure. */ - string error; + /* Error message after running, in case of failure. */ + string error; - /* Sequential list of frame filepaths to denoise. */ - vector<string> input; - /* Sequential list of frame filepaths to write result to. Empty entries - * are skipped, so only a subset of the sequence can be denoised while - * taking into account all input frames. */ - vector<string> output; + /* Sequential list of frame filepaths to denoise. */ + vector<string> input; + /* Sequential list of frame filepaths to write result to. Empty entries + * are skipped, so only a subset of the sequence can be denoised while + * taking into account all input frames. */ + vector<string> output; - /* Sample number override, takes precedence over values from input frames. */ - int samples_override; - /* Tile size for processing on device. */ - int2 tile_size; + /* Sample number override, takes precedence over values from input frames. */ + int samples_override; + /* Tile size for processing on device. */ + int2 tile_size; - /* Equivalent to the settings in the regular denoiser. */ - DenoiseParams params; + /* Equivalent to the settings in the regular denoiser. */ + DenoiseParams params; -protected: - friend class DenoiseTask; + protected: + friend class DenoiseTask; - Stats stats; - Profiler profiler; - Device *device; + Stats stats; + Profiler profiler; + Device *device; - int num_frames; + int num_frames; }; /* Denoise Image Layer */ struct DenoiseImageLayer { - string name; - /* All channels belonging to this DenoiseImageLayer. */ - vector<string> channels; - /* Layer to image channel mapping. */ - vector<int> layer_to_image_channel; + string name; + /* All channels belonging to this DenoiseImageLayer. */ + vector<string> channels; + /* Layer to image channel mapping. */ + vector<int> layer_to_image_channel; - /* Sample amount that was used for rendering this layer. */ - int samples; + /* Sample amount that was used for rendering this layer. */ + int samples; - /* Device input channel will be copied from image channel input_to_image_channel[i]. */ - vector<int> input_to_image_channel; + /* Device input channel will be copied from image channel input_to_image_channel[i]. */ + vector<int> input_to_image_channel; - /* input_to_image_channel of the secondary frames, if any are used. */ - vector<vector<int>> neighbor_input_to_image_channel; + /* input_to_image_channel of the secondary frames, if any are used. */ + vector<vector<int>> neighbor_input_to_image_channel; - /* Write i-th channel of the processing output to output_to_image_channel[i]-th channel of the file. */ - vector<int> output_to_image_channel; + /* Write i-th channel of the processing output to output_to_image_channel[i]-th channel of the file. */ + vector<int> output_to_image_channel; - /* Detect whether this layer contains a full set of channels and set up the offsets accordingly. */ - bool detect_denoising_channels(); + /* Detect whether this layer contains a full set of channels and set up the offsets accordingly. */ + bool detect_denoising_channels(); - /* Map the channels of a secondary frame to the channels that are required for processing, - * fill neighbor_input_to_image_channel if all are present or return false if a channel are missing. */ - bool match_channels(int neighbor, - const std::vector<string> &channelnames, - const std::vector<string> &neighbor_channelnames); + /* Map the channels of a secondary frame to the channels that are required for processing, + * fill neighbor_input_to_image_channel if all are present or return false if a channel are missing. */ + bool match_channels(int neighbor, + const std::vector<string> &channelnames, + const std::vector<string> &neighbor_channelnames); }; /* Denoise Image Data */ class DenoiseImage { -public: - DenoiseImage(); - ~DenoiseImage(); + public: + DenoiseImage(); + ~DenoiseImage(); - /* Dimensions */ - int width, height, num_channels; + /* Dimensions */ + int width, height, num_channels; - /* Samples */ - int samples; + /* Samples */ + int samples; - /* Pixel buffer with interleaved channels. */ - array<float> pixels; + /* Pixel buffer with interleaved channels. */ + array<float> pixels; - /* Image file handles */ - ImageSpec in_spec; - vector<unique_ptr<ImageInput>> in_neighbors; + /* Image file handles */ + ImageSpec in_spec; + vector<unique_ptr<ImageInput>> in_neighbors; - /* Render layers */ - vector<DenoiseImageLayer> layers; + /* Render layers */ + vector<DenoiseImageLayer> layers; - void free(); + void free(); - /* Open the input image, parse its channels, open the output image and allocate the output buffer. */ - bool load(const string& in_filepath, string& error); + /* Open the input image, parse its channels, open the output image and allocate the output buffer. */ + bool load(const string &in_filepath, string &error); - /* Load neighboring frames. */ - bool load_neighbors(const vector<string>& filepaths, const vector<int>& frames, string& error); + /* Load neighboring frames. */ + bool load_neighbors(const vector<string> &filepaths, const vector<int> &frames, string &error); - /* Load subset of pixels from file buffer into input buffer, as needed for denoising - * on the device. Channels are reshuffled following the provided mapping. */ - void read_pixels(const DenoiseImageLayer& layer, float *input_pixels); - bool read_neighbor_pixels(int neighbor, const DenoiseImageLayer& layer, float *input_pixels); + /* Load subset of pixels from file buffer into input buffer, as needed for denoising + * on the device. Channels are reshuffled following the provided mapping. */ + void read_pixels(const DenoiseImageLayer &layer, float *input_pixels); + bool read_neighbor_pixels(int neighbor, const DenoiseImageLayer &layer, float *input_pixels); - bool save_output(const string& out_filepath, string& error); + bool save_output(const string &out_filepath, string &error); -protected: - /* Parse input file channels, separate them into DenoiseImageLayers, detect DenoiseImageLayers with full channel sets, - * fill layers and set up the output channels and passthrough map. */ - bool parse_channels(const ImageSpec &in_spec, string& error); + protected: + /* Parse input file channels, separate them into DenoiseImageLayers, detect DenoiseImageLayers with full channel sets, + * fill layers and set up the output channels and passthrough map. */ + bool parse_channels(const ImageSpec &in_spec, string &error); - void close_input(); + void close_input(); }; /* Denoise Task */ class DenoiseTask { -public: - DenoiseTask(Device *device, Denoiser *denoiser, int frame, const vector<int>& neighbor_frames); - ~DenoiseTask(); - - /* Task stages */ - bool load(); - bool exec(); - bool save(); - void free(); - - string error; - -protected: - /* Denoiser parameters and device */ - Denoiser *denoiser; - Device *device; - - /* Frame number to be denoised */ - int frame; - vector<int> neighbor_frames; - - /* Image file data */ - DenoiseImage image; - int current_layer; - - /* Device input buffer */ - device_vector<float> input_pixels; - - /* Tiles */ - thread_mutex tiles_mutex; - list<RenderTile> tiles; - int num_tiles; - - thread_mutex output_mutex; - map<int, device_vector<float>*> output_pixels; - - /* Task handling */ - bool load_input_pixels(int layer); - void create_task(DeviceTask& task); - - /* Device task callbacks */ - bool acquire_tile(Device *device, Device *tile_device, RenderTile &tile); - void map_neighboring_tiles(RenderTile *tiles, Device *tile_device); - void unmap_neighboring_tiles(RenderTile *tiles); - void release_tile(); - bool get_cancel(); + public: + DenoiseTask(Device *device, Denoiser *denoiser, int frame, const vector<int> &neighbor_frames); + ~DenoiseTask(); + + /* Task stages */ + bool load(); + bool exec(); + bool save(); + void free(); + + string error; + + protected: + /* Denoiser parameters and device */ + Denoiser *denoiser; + Device *device; + + /* Frame number to be denoised */ + int frame; + vector<int> neighbor_frames; + + /* Image file data */ + DenoiseImage image; + int current_layer; + + /* Device input buffer */ + device_vector<float> input_pixels; + + /* Tiles */ + thread_mutex tiles_mutex; + list<RenderTile> tiles; + int num_tiles; + + thread_mutex output_mutex; + map<int, device_vector<float> *> output_pixels; + + /* Task handling */ + bool load_input_pixels(int layer); + void create_task(DeviceTask &task); + + /* Device task callbacks */ + bool acquire_tile(Device *device, Device *tile_device, RenderTile &tile); + void map_neighboring_tiles(RenderTile *tiles, Device *tile_device); + void unmap_neighboring_tiles(RenderTile *tiles); + void release_tile(); + bool get_cancel(); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 1d1668a20d1..d6c44b66117 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -31,277 +31,275 @@ CCL_NAMESPACE_BEGIN /* Pass */ -static bool compare_pass_order(const Pass& a, const Pass& b) +static bool compare_pass_order(const Pass &a, const Pass &b) { - if(a.components == b.components) - return (a.type < b.type); - return (a.components > b.components); + if (a.components == b.components) + return (a.type < b.type); + return (a.components > b.components); } -void Pass::add(PassType type, vector<Pass>& passes, const char *name) +void Pass::add(PassType type, vector<Pass> &passes, const char *name) { - for(size_t i = 0; i < passes.size(); i++) { - if(passes[i].type == type && - (name ? (passes[i].name == name) : passes[i].name.empty())) { - return; - } - } - - Pass pass; - - pass.type = type; - pass.filter = true; - pass.exposure = false; - pass.divide_type = PASS_NONE; - if(name) { - pass.name = name; - } - - switch(type) { - case PASS_NONE: - pass.components = 0; - break; - case PASS_COMBINED: - pass.components = 4; - pass.exposure = true; - break; - case PASS_DEPTH: - pass.components = 1; - pass.filter = false; - break; - case PASS_MIST: - pass.components = 1; - break; - case PASS_NORMAL: - pass.components = 4; - break; - case PASS_UV: - pass.components = 4; - break; - case PASS_MOTION: - pass.components = 4; - pass.divide_type = PASS_MOTION_WEIGHT; - break; - case PASS_MOTION_WEIGHT: - pass.components = 1; - break; - case PASS_OBJECT_ID: - case PASS_MATERIAL_ID: - pass.components = 1; - pass.filter = false; - break; - - case PASS_EMISSION: - case PASS_BACKGROUND: - pass.components = 4; - pass.exposure = true; - break; - case PASS_AO: - pass.components = 4; - break; - case PASS_SHADOW: - pass.components = 4; - pass.exposure = false; - break; - case PASS_LIGHT: - /* This isn't a real pass, used by baking to see whether - * light data is needed or not. - * - * Set components to 0 so pass sort below happens in a - * determined way. - */ - pass.components = 0; - break; + for (size_t i = 0; i < passes.size(); i++) { + if (passes[i].type == type && (name ? (passes[i].name == name) : passes[i].name.empty())) { + return; + } + } + + Pass pass; + + pass.type = type; + pass.filter = true; + pass.exposure = false; + pass.divide_type = PASS_NONE; + if (name) { + pass.name = name; + } + + switch (type) { + case PASS_NONE: + pass.components = 0; + break; + case PASS_COMBINED: + pass.components = 4; + pass.exposure = true; + break; + case PASS_DEPTH: + pass.components = 1; + pass.filter = false; + break; + case PASS_MIST: + pass.components = 1; + break; + case PASS_NORMAL: + pass.components = 4; + break; + case PASS_UV: + pass.components = 4; + break; + case PASS_MOTION: + pass.components = 4; + pass.divide_type = PASS_MOTION_WEIGHT; + break; + case PASS_MOTION_WEIGHT: + pass.components = 1; + break; + case PASS_OBJECT_ID: + case PASS_MATERIAL_ID: + pass.components = 1; + pass.filter = false; + break; + + case PASS_EMISSION: + case PASS_BACKGROUND: + pass.components = 4; + pass.exposure = true; + break; + case PASS_AO: + pass.components = 4; + break; + case PASS_SHADOW: + pass.components = 4; + pass.exposure = false; + break; + case PASS_LIGHT: + /* This isn't a real pass, used by baking to see whether + * light data is needed or not. + * + * Set components to 0 so pass sort below happens in a + * determined way. + */ + pass.components = 0; + break; #ifdef WITH_CYCLES_DEBUG - case PASS_BVH_TRAVERSED_NODES: - case PASS_BVH_TRAVERSED_INSTANCES: - case PASS_BVH_INTERSECTIONS: - case PASS_RAY_BOUNCES: - pass.components = 1; - pass.exposure = false; - break; + case PASS_BVH_TRAVERSED_NODES: + case PASS_BVH_TRAVERSED_INSTANCES: + case PASS_BVH_INTERSECTIONS: + case PASS_RAY_BOUNCES: + pass.components = 1; + pass.exposure = false; + break; #endif - case PASS_RENDER_TIME: - /* This pass is handled entirely on the host side. */ - pass.components = 0; - break; - - case PASS_DIFFUSE_COLOR: - case PASS_GLOSSY_COLOR: - case PASS_TRANSMISSION_COLOR: - case PASS_SUBSURFACE_COLOR: - pass.components = 4; - break; - case PASS_DIFFUSE_DIRECT: - case PASS_DIFFUSE_INDIRECT: - pass.components = 4; - pass.exposure = true; - pass.divide_type = PASS_DIFFUSE_COLOR; - break; - case PASS_GLOSSY_DIRECT: - case PASS_GLOSSY_INDIRECT: - pass.components = 4; - pass.exposure = true; - pass.divide_type = PASS_GLOSSY_COLOR; - break; - case PASS_TRANSMISSION_DIRECT: - case PASS_TRANSMISSION_INDIRECT: - pass.components = 4; - pass.exposure = true; - pass.divide_type = PASS_TRANSMISSION_COLOR; - break; - case PASS_SUBSURFACE_DIRECT: - case PASS_SUBSURFACE_INDIRECT: - pass.components = 4; - pass.exposure = true; - pass.divide_type = PASS_SUBSURFACE_COLOR; - break; - case PASS_VOLUME_DIRECT: - case PASS_VOLUME_INDIRECT: - pass.components = 4; - pass.exposure = true; - break; - case PASS_CRYPTOMATTE: - pass.components = 4; - break; - default: - assert(false); - break; - } - - passes.push_back(pass); - - /* order from by components, to ensure alignment so passes with size 4 - * come first and then passes with size 1 */ - sort(&passes[0], &passes[0] + passes.size(), compare_pass_order); - - if(pass.divide_type != PASS_NONE) - Pass::add(pass.divide_type, passes); + case PASS_RENDER_TIME: + /* This pass is handled entirely on the host side. */ + pass.components = 0; + break; + + case PASS_DIFFUSE_COLOR: + case PASS_GLOSSY_COLOR: + case PASS_TRANSMISSION_COLOR: + case PASS_SUBSURFACE_COLOR: + pass.components = 4; + break; + case PASS_DIFFUSE_DIRECT: + case PASS_DIFFUSE_INDIRECT: + pass.components = 4; + pass.exposure = true; + pass.divide_type = PASS_DIFFUSE_COLOR; + break; + case PASS_GLOSSY_DIRECT: + case PASS_GLOSSY_INDIRECT: + pass.components = 4; + pass.exposure = true; + pass.divide_type = PASS_GLOSSY_COLOR; + break; + case PASS_TRANSMISSION_DIRECT: + case PASS_TRANSMISSION_INDIRECT: + pass.components = 4; + pass.exposure = true; + pass.divide_type = PASS_TRANSMISSION_COLOR; + break; + case PASS_SUBSURFACE_DIRECT: + case PASS_SUBSURFACE_INDIRECT: + pass.components = 4; + pass.exposure = true; + pass.divide_type = PASS_SUBSURFACE_COLOR; + break; + case PASS_VOLUME_DIRECT: + case PASS_VOLUME_INDIRECT: + pass.components = 4; + pass.exposure = true; + break; + case PASS_CRYPTOMATTE: + pass.components = 4; + break; + default: + assert(false); + break; + } + + passes.push_back(pass); + + /* order from by components, to ensure alignment so passes with size 4 + * come first and then passes with size 1 */ + sort(&passes[0], &passes[0] + passes.size(), compare_pass_order); + + if (pass.divide_type != PASS_NONE) + Pass::add(pass.divide_type, passes); } -bool Pass::equals(const vector<Pass>& A, const vector<Pass>& B) +bool Pass::equals(const vector<Pass> &A, const vector<Pass> &B) { - if(A.size() != B.size()) - return false; + if (A.size() != B.size()) + return false; - for(int i = 0; i < A.size(); i++) - if(A[i].type != B[i].type || A[i].name != B[i].name) - return false; + for (int i = 0; i < A.size(); i++) + if (A[i].type != B[i].type || A[i].name != B[i].name) + return false; - return true; + return true; } -bool Pass::contains(const vector<Pass>& passes, PassType type) +bool Pass::contains(const vector<Pass> &passes, PassType type) { - for(size_t i = 0; i < passes.size(); i++) - if(passes[i].type == type) - return true; + for (size_t i = 0; i < passes.size(); i++) + if (passes[i].type == type) + return true; - return false; + return false; } /* Pixel Filter */ static float filter_func_box(float /*v*/, float /*width*/) { - return 1.0f; + return 1.0f; } static float filter_func_gaussian(float v, float width) { - v *= 6.0f/width; - return expf(-2.0f*v*v); + v *= 6.0f / width; + return expf(-2.0f * v * v); } static float filter_func_blackman_harris(float v, float width) { - v = M_2PI_F * (v / width + 0.5f); - return 0.35875f - 0.48829f*cosf(v) + 0.14128f*cosf(2.0f*v) - 0.01168f*cosf(3.0f*v); + v = M_2PI_F * (v / width + 0.5f); + return 0.35875f - 0.48829f * cosf(v) + 0.14128f * cosf(2.0f * v) - 0.01168f * cosf(3.0f * v); } static vector<float> filter_table(FilterType type, float width) { - vector<float> filter_table(FILTER_TABLE_SIZE); - float (*filter_func)(float, float) = NULL; - - switch(type) { - case FILTER_BOX: - filter_func = filter_func_box; - break; - case FILTER_GAUSSIAN: - filter_func = filter_func_gaussian; - width *= 3.0f; - break; - case FILTER_BLACKMAN_HARRIS: - filter_func = filter_func_blackman_harris; - width *= 2.0f; - break; - default: - assert(0); - } - - /* Create importance sampling table. */ - - /* TODO(sergey): With the even filter table size resolution we can not - * really make it nice symmetric importance map without sampling full range - * (meaning, we would need to sample full filter range and not use the - * make_symmetric argument). - * - * Current code matches exactly initial filter table code, but we should - * consider either making FILTER_TABLE_SIZE odd value or sample full filter. - */ - - util_cdf_inverted(FILTER_TABLE_SIZE, - 0.0f, - width * 0.5f, - function_bind(filter_func, _1, width), - true, - filter_table); - - return filter_table; + vector<float> filter_table(FILTER_TABLE_SIZE); + float (*filter_func)(float, float) = NULL; + + switch (type) { + case FILTER_BOX: + filter_func = filter_func_box; + break; + case FILTER_GAUSSIAN: + filter_func = filter_func_gaussian; + width *= 3.0f; + break; + case FILTER_BLACKMAN_HARRIS: + filter_func = filter_func_blackman_harris; + width *= 2.0f; + break; + default: + assert(0); + } + + /* Create importance sampling table. */ + + /* TODO(sergey): With the even filter table size resolution we can not + * really make it nice symmetric importance map without sampling full range + * (meaning, we would need to sample full filter range and not use the + * make_symmetric argument). + * + * Current code matches exactly initial filter table code, but we should + * consider either making FILTER_TABLE_SIZE odd value or sample full filter. + */ + + util_cdf_inverted(FILTER_TABLE_SIZE, + 0.0f, + width * 0.5f, + function_bind(filter_func, _1, width), + true, + filter_table); + + return filter_table; } /* Film */ NODE_DEFINE(Film) { - NodeType* type = NodeType::add("film", create); + NodeType *type = NodeType::add("film", create); - SOCKET_FLOAT(exposure, "Exposure", 0.8f); - SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.5f); + SOCKET_FLOAT(exposure, "Exposure", 0.8f); + SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.5f); - static NodeEnum filter_enum; - filter_enum.insert("box", FILTER_BOX); - filter_enum.insert("gaussian", FILTER_GAUSSIAN); - filter_enum.insert("blackman_harris", FILTER_BLACKMAN_HARRIS); + static NodeEnum filter_enum; + filter_enum.insert("box", FILTER_BOX); + filter_enum.insert("gaussian", FILTER_GAUSSIAN); + filter_enum.insert("blackman_harris", FILTER_BLACKMAN_HARRIS); - SOCKET_ENUM(filter_type, "Filter Type", filter_enum, FILTER_BOX); - SOCKET_FLOAT(filter_width, "Filter Width", 1.0f); + SOCKET_ENUM(filter_type, "Filter Type", filter_enum, FILTER_BOX); + SOCKET_FLOAT(filter_width, "Filter Width", 1.0f); - SOCKET_FLOAT(mist_start, "Mist Start", 0.0f); - SOCKET_FLOAT(mist_depth, "Mist Depth", 100.0f); - SOCKET_FLOAT(mist_falloff, "Mist Falloff", 1.0f); + SOCKET_FLOAT(mist_start, "Mist Start", 0.0f); + SOCKET_FLOAT(mist_depth, "Mist Depth", 100.0f); + SOCKET_FLOAT(mist_falloff, "Mist Falloff", 1.0f); - SOCKET_BOOLEAN(use_sample_clamp, "Use Sample Clamp", false); + SOCKET_BOOLEAN(use_sample_clamp, "Use Sample Clamp", false); - SOCKET_BOOLEAN(denoising_data_pass, "Generate Denoising Data Pass", false); - SOCKET_BOOLEAN(denoising_clean_pass, "Generate Denoising Clean Pass", false); - SOCKET_BOOLEAN(denoising_prefiltered_pass, "Generate Denoising Prefiltered Pass", false); - SOCKET_INT(denoising_flags, "Denoising Flags", 0); + SOCKET_BOOLEAN(denoising_data_pass, "Generate Denoising Data Pass", false); + SOCKET_BOOLEAN(denoising_clean_pass, "Generate Denoising Clean Pass", false); + SOCKET_BOOLEAN(denoising_prefiltered_pass, "Generate Denoising Prefiltered Pass", false); + SOCKET_INT(denoising_flags, "Denoising Flags", 0); - return type; + return type; } -Film::Film() -: Node(node_type) +Film::Film() : Node(node_type) { - Pass::add(PASS_COMBINED, passes); + Pass::add(PASS_COMBINED, passes); - use_light_visibility = false; - filter_table_offset = TABLE_OFFSET_INVALID; - cryptomatte_passes = CRYPT_NONE; + use_light_visibility = false; + filter_table_offset = TABLE_OFFSET_INVALID; + cryptomatte_passes = CRYPT_NONE; - need_update = true; + need_update = true; } Film::~Film() @@ -310,233 +308,233 @@ Film::~Film() void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene) { - if(!need_update) - return; - - device_free(device, dscene, scene); - - KernelFilm *kfilm = &dscene->data.film; - - /* update __data */ - kfilm->exposure = exposure; - kfilm->pass_flag = 0; - kfilm->light_pass_flag = 0; - kfilm->pass_stride = 0; - kfilm->use_light_pass = use_light_visibility || use_sample_clamp; - - bool have_cryptomatte = false; - - for(size_t i = 0; i < passes.size(); i++) { - Pass& pass = passes[i]; - - if(pass.type == PASS_NONE) { - continue; - } - - /* Can't do motion pass if no motion vectors are available. */ - if (pass.type == PASS_MOTION || pass.type == PASS_MOTION_WEIGHT) { - if (scene->need_motion() != Scene::MOTION_PASS) { - kfilm->pass_stride += pass.components; - continue; - } - } - - int pass_flag = (1 << (pass.type % 32)); - if(pass.type <= PASS_CATEGORY_MAIN_END) { - kfilm->pass_flag |= pass_flag; - } - else { - assert(pass.type <= PASS_CATEGORY_LIGHT_END); - kfilm->use_light_pass = 1; - kfilm->light_pass_flag |= pass_flag; - } - - switch(pass.type) { - case PASS_COMBINED: - kfilm->pass_combined = kfilm->pass_stride; - break; - case PASS_DEPTH: - kfilm->pass_depth = kfilm->pass_stride; - break; - case PASS_NORMAL: - kfilm->pass_normal = kfilm->pass_stride; - break; - case PASS_UV: - kfilm->pass_uv = kfilm->pass_stride; - break; - case PASS_MOTION: - kfilm->pass_motion = kfilm->pass_stride; - break; - case PASS_MOTION_WEIGHT: - kfilm->pass_motion_weight = kfilm->pass_stride; - break; - case PASS_OBJECT_ID: - kfilm->pass_object_id = kfilm->pass_stride; - break; - case PASS_MATERIAL_ID: - kfilm->pass_material_id = kfilm->pass_stride; - break; - - case PASS_MIST: - kfilm->pass_mist = kfilm->pass_stride; - break; - case PASS_EMISSION: - kfilm->pass_emission = kfilm->pass_stride; - break; - case PASS_BACKGROUND: - kfilm->pass_background = kfilm->pass_stride; - break; - case PASS_AO: - kfilm->pass_ao = kfilm->pass_stride; - break; - case PASS_SHADOW: - kfilm->pass_shadow = kfilm->pass_stride; - break; - - case PASS_LIGHT: - break; - - case PASS_DIFFUSE_COLOR: - kfilm->pass_diffuse_color = kfilm->pass_stride; - break; - case PASS_GLOSSY_COLOR: - kfilm->pass_glossy_color = kfilm->pass_stride; - break; - case PASS_TRANSMISSION_COLOR: - kfilm->pass_transmission_color = kfilm->pass_stride; - break; - case PASS_SUBSURFACE_COLOR: - kfilm->pass_subsurface_color = kfilm->pass_stride; - break; - case PASS_DIFFUSE_INDIRECT: - kfilm->pass_diffuse_indirect = kfilm->pass_stride; - break; - case PASS_GLOSSY_INDIRECT: - kfilm->pass_glossy_indirect = kfilm->pass_stride; - break; - case PASS_TRANSMISSION_INDIRECT: - kfilm->pass_transmission_indirect = kfilm->pass_stride; - break; - case PASS_SUBSURFACE_INDIRECT: - kfilm->pass_subsurface_indirect = kfilm->pass_stride; - break; - case PASS_VOLUME_INDIRECT: - kfilm->pass_volume_indirect = kfilm->pass_stride; - break; - case PASS_DIFFUSE_DIRECT: - kfilm->pass_diffuse_direct = kfilm->pass_stride; - break; - case PASS_GLOSSY_DIRECT: - kfilm->pass_glossy_direct = kfilm->pass_stride; - break; - case PASS_TRANSMISSION_DIRECT: - kfilm->pass_transmission_direct = kfilm->pass_stride; - break; - case PASS_SUBSURFACE_DIRECT: - kfilm->pass_subsurface_direct = kfilm->pass_stride; - break; - case PASS_VOLUME_DIRECT: - kfilm->pass_volume_direct = kfilm->pass_stride; - break; + if (!need_update) + return; + + device_free(device, dscene, scene); + + KernelFilm *kfilm = &dscene->data.film; + + /* update __data */ + kfilm->exposure = exposure; + kfilm->pass_flag = 0; + kfilm->light_pass_flag = 0; + kfilm->pass_stride = 0; + kfilm->use_light_pass = use_light_visibility || use_sample_clamp; + + bool have_cryptomatte = false; + + for (size_t i = 0; i < passes.size(); i++) { + Pass &pass = passes[i]; + + if (pass.type == PASS_NONE) { + continue; + } + + /* Can't do motion pass if no motion vectors are available. */ + if (pass.type == PASS_MOTION || pass.type == PASS_MOTION_WEIGHT) { + if (scene->need_motion() != Scene::MOTION_PASS) { + kfilm->pass_stride += pass.components; + continue; + } + } + + int pass_flag = (1 << (pass.type % 32)); + if (pass.type <= PASS_CATEGORY_MAIN_END) { + kfilm->pass_flag |= pass_flag; + } + else { + assert(pass.type <= PASS_CATEGORY_LIGHT_END); + kfilm->use_light_pass = 1; + kfilm->light_pass_flag |= pass_flag; + } + + switch (pass.type) { + case PASS_COMBINED: + kfilm->pass_combined = kfilm->pass_stride; + break; + case PASS_DEPTH: + kfilm->pass_depth = kfilm->pass_stride; + break; + case PASS_NORMAL: + kfilm->pass_normal = kfilm->pass_stride; + break; + case PASS_UV: + kfilm->pass_uv = kfilm->pass_stride; + break; + case PASS_MOTION: + kfilm->pass_motion = kfilm->pass_stride; + break; + case PASS_MOTION_WEIGHT: + kfilm->pass_motion_weight = kfilm->pass_stride; + break; + case PASS_OBJECT_ID: + kfilm->pass_object_id = kfilm->pass_stride; + break; + case PASS_MATERIAL_ID: + kfilm->pass_material_id = kfilm->pass_stride; + break; + + case PASS_MIST: + kfilm->pass_mist = kfilm->pass_stride; + break; + case PASS_EMISSION: + kfilm->pass_emission = kfilm->pass_stride; + break; + case PASS_BACKGROUND: + kfilm->pass_background = kfilm->pass_stride; + break; + case PASS_AO: + kfilm->pass_ao = kfilm->pass_stride; + break; + case PASS_SHADOW: + kfilm->pass_shadow = kfilm->pass_stride; + break; + + case PASS_LIGHT: + break; + + case PASS_DIFFUSE_COLOR: + kfilm->pass_diffuse_color = kfilm->pass_stride; + break; + case PASS_GLOSSY_COLOR: + kfilm->pass_glossy_color = kfilm->pass_stride; + break; + case PASS_TRANSMISSION_COLOR: + kfilm->pass_transmission_color = kfilm->pass_stride; + break; + case PASS_SUBSURFACE_COLOR: + kfilm->pass_subsurface_color = kfilm->pass_stride; + break; + case PASS_DIFFUSE_INDIRECT: + kfilm->pass_diffuse_indirect = kfilm->pass_stride; + break; + case PASS_GLOSSY_INDIRECT: + kfilm->pass_glossy_indirect = kfilm->pass_stride; + break; + case PASS_TRANSMISSION_INDIRECT: + kfilm->pass_transmission_indirect = kfilm->pass_stride; + break; + case PASS_SUBSURFACE_INDIRECT: + kfilm->pass_subsurface_indirect = kfilm->pass_stride; + break; + case PASS_VOLUME_INDIRECT: + kfilm->pass_volume_indirect = kfilm->pass_stride; + break; + case PASS_DIFFUSE_DIRECT: + kfilm->pass_diffuse_direct = kfilm->pass_stride; + break; + case PASS_GLOSSY_DIRECT: + kfilm->pass_glossy_direct = kfilm->pass_stride; + break; + case PASS_TRANSMISSION_DIRECT: + kfilm->pass_transmission_direct = kfilm->pass_stride; + break; + case PASS_SUBSURFACE_DIRECT: + kfilm->pass_subsurface_direct = kfilm->pass_stride; + break; + case PASS_VOLUME_DIRECT: + kfilm->pass_volume_direct = kfilm->pass_stride; + break; #ifdef WITH_CYCLES_DEBUG - case PASS_BVH_TRAVERSED_NODES: - kfilm->pass_bvh_traversed_nodes = kfilm->pass_stride; - break; - case PASS_BVH_TRAVERSED_INSTANCES: - kfilm->pass_bvh_traversed_instances = kfilm->pass_stride; - break; - case PASS_BVH_INTERSECTIONS: - kfilm->pass_bvh_intersections = kfilm->pass_stride; - break; - case PASS_RAY_BOUNCES: - kfilm->pass_ray_bounces = kfilm->pass_stride; - break; + case PASS_BVH_TRAVERSED_NODES: + kfilm->pass_bvh_traversed_nodes = kfilm->pass_stride; + break; + case PASS_BVH_TRAVERSED_INSTANCES: + kfilm->pass_bvh_traversed_instances = kfilm->pass_stride; + break; + case PASS_BVH_INTERSECTIONS: + kfilm->pass_bvh_intersections = kfilm->pass_stride; + break; + case PASS_RAY_BOUNCES: + kfilm->pass_ray_bounces = kfilm->pass_stride; + break; #endif - case PASS_RENDER_TIME: - break; - case PASS_CRYPTOMATTE: - kfilm->pass_cryptomatte = have_cryptomatte ? min(kfilm->pass_cryptomatte, kfilm->pass_stride) : kfilm->pass_stride; - have_cryptomatte = true; - break; - default: - assert(false); - break; - } - - kfilm->pass_stride += pass.components; - } - - kfilm->pass_denoising_data = 0; - kfilm->pass_denoising_clean = 0; - kfilm->denoising_flags = 0; - if(denoising_data_pass) { - kfilm->pass_denoising_data = kfilm->pass_stride; - kfilm->pass_stride += DENOISING_PASS_SIZE_BASE; - kfilm->denoising_flags = denoising_flags; - if(denoising_clean_pass) { - kfilm->pass_denoising_clean = kfilm->pass_stride; - kfilm->pass_stride += DENOISING_PASS_SIZE_CLEAN; - kfilm->use_light_pass = 1; - } - if(denoising_prefiltered_pass) { - kfilm->pass_stride += DENOISING_PASS_SIZE_PREFILTERED; - } - } - - kfilm->pass_stride = align_up(kfilm->pass_stride, 4); - kfilm->pass_alpha_threshold = pass_alpha_threshold; - - /* update filter table */ - vector<float> table = filter_table(filter_type, filter_width); - scene->lookup_tables->remove_table(&filter_table_offset); - filter_table_offset = scene->lookup_tables->add_table(dscene, table); - kfilm->filter_table_offset = (int)filter_table_offset; - - /* mist pass parameters */ - kfilm->mist_start = mist_start; - kfilm->mist_inv_depth = (mist_depth > 0.0f)? 1.0f/mist_depth: 0.0f; - kfilm->mist_falloff = mist_falloff; - - kfilm->cryptomatte_passes = cryptomatte_passes; - kfilm->cryptomatte_depth = cryptomatte_depth; - - pass_stride = kfilm->pass_stride; - denoising_data_offset = kfilm->pass_denoising_data; - denoising_clean_offset = kfilm->pass_denoising_clean; - - need_update = false; + case PASS_RENDER_TIME: + break; + case PASS_CRYPTOMATTE: + kfilm->pass_cryptomatte = have_cryptomatte ? + min(kfilm->pass_cryptomatte, kfilm->pass_stride) : + kfilm->pass_stride; + have_cryptomatte = true; + break; + default: + assert(false); + break; + } + + kfilm->pass_stride += pass.components; + } + + kfilm->pass_denoising_data = 0; + kfilm->pass_denoising_clean = 0; + kfilm->denoising_flags = 0; + if (denoising_data_pass) { + kfilm->pass_denoising_data = kfilm->pass_stride; + kfilm->pass_stride += DENOISING_PASS_SIZE_BASE; + kfilm->denoising_flags = denoising_flags; + if (denoising_clean_pass) { + kfilm->pass_denoising_clean = kfilm->pass_stride; + kfilm->pass_stride += DENOISING_PASS_SIZE_CLEAN; + kfilm->use_light_pass = 1; + } + if (denoising_prefiltered_pass) { + kfilm->pass_stride += DENOISING_PASS_SIZE_PREFILTERED; + } + } + + kfilm->pass_stride = align_up(kfilm->pass_stride, 4); + kfilm->pass_alpha_threshold = pass_alpha_threshold; + + /* update filter table */ + vector<float> table = filter_table(filter_type, filter_width); + scene->lookup_tables->remove_table(&filter_table_offset); + filter_table_offset = scene->lookup_tables->add_table(dscene, table); + kfilm->filter_table_offset = (int)filter_table_offset; + + /* mist pass parameters */ + kfilm->mist_start = mist_start; + kfilm->mist_inv_depth = (mist_depth > 0.0f) ? 1.0f / mist_depth : 0.0f; + kfilm->mist_falloff = mist_falloff; + + kfilm->cryptomatte_passes = cryptomatte_passes; + kfilm->cryptomatte_depth = cryptomatte_depth; + + pass_stride = kfilm->pass_stride; + denoising_data_offset = kfilm->pass_denoising_data; + denoising_clean_offset = kfilm->pass_denoising_clean; + + need_update = false; } -void Film::device_free(Device * /*device*/, - DeviceScene * /*dscene*/, - Scene *scene) +void Film::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene *scene) { - scene->lookup_tables->remove_table(&filter_table_offset); + scene->lookup_tables->remove_table(&filter_table_offset); } -bool Film::modified(const Film& film) +bool Film::modified(const Film &film) { - return !Node::equals(film) || !Pass::equals(passes, film.passes); + return !Node::equals(film) || !Pass::equals(passes, film.passes); } -void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_) +void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_) { - if(Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) { - scene->mesh_manager->tag_update(scene); + if (Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) { + scene->mesh_manager->tag_update(scene); - foreach(Shader *shader, scene->shaders) - shader->need_update_mesh = true; - } - else if(Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) - scene->mesh_manager->tag_update(scene); + foreach (Shader *shader, scene->shaders) + shader->need_update_mesh = true; + } + else if (Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) + scene->mesh_manager->tag_update(scene); - passes = passes_; + passes = passes_; } void Film::tag_update(Scene * /*scene*/) { - need_update = true; + need_update = true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h index 8330a4cf413..1cfa7c3b77d 100644 --- a/intern/cycles/render/film.h +++ b/intern/cycles/render/film.h @@ -31,69 +31,69 @@ class DeviceScene; class Scene; typedef enum FilterType { - FILTER_BOX, - FILTER_GAUSSIAN, - FILTER_BLACKMAN_HARRIS, + FILTER_BOX, + FILTER_GAUSSIAN, + FILTER_BLACKMAN_HARRIS, - FILTER_NUM_TYPES, + FILTER_NUM_TYPES, } FilterType; class Pass { -public: - PassType type; - int components; - bool filter; - bool exposure; - PassType divide_type; - string name; - - static void add(PassType type, vector<Pass>& passes, const char* name = NULL); - static bool equals(const vector<Pass>& A, const vector<Pass>& B); - static bool contains(const vector<Pass>& passes, PassType); + public: + PassType type; + int components; + bool filter; + bool exposure; + PassType divide_type; + string name; + + static void add(PassType type, vector<Pass> &passes, const char *name = NULL); + static bool equals(const vector<Pass> &A, const vector<Pass> &B); + static bool contains(const vector<Pass> &passes, PassType); }; class Film : public Node { -public: - NODE_DECLARE + public: + NODE_DECLARE - float exposure; - vector<Pass> passes; - bool denoising_data_pass; - bool denoising_clean_pass; - bool denoising_prefiltered_pass; - int denoising_flags; - float pass_alpha_threshold; + float exposure; + vector<Pass> passes; + bool denoising_data_pass; + bool denoising_clean_pass; + bool denoising_prefiltered_pass; + int denoising_flags; + float pass_alpha_threshold; - int pass_stride; - int denoising_data_offset; - int denoising_clean_offset; + int pass_stride; + int denoising_data_offset; + int denoising_clean_offset; - FilterType filter_type; - float filter_width; - size_t filter_table_offset; + FilterType filter_type; + float filter_width; + size_t filter_table_offset; - float mist_start; - float mist_depth; - float mist_falloff; + float mist_start; + float mist_depth; + float mist_falloff; - bool use_light_visibility; - bool use_sample_clamp; - CryptomatteType cryptomatte_passes; - int cryptomatte_depth; + bool use_light_visibility; + bool use_sample_clamp; + CryptomatteType cryptomatte_passes; + int cryptomatte_depth; - bool need_update; + bool need_update; - Film(); - ~Film(); + Film(); + ~Film(); - void device_update(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene, Scene *scene); + void device_update(Device *device, DeviceScene *dscene, Scene *scene); + void device_free(Device *device, DeviceScene *dscene, Scene *scene); - bool modified(const Film& film); - void tag_passes_update(Scene *scene, const vector<Pass>& passes_); - void tag_update(Scene *scene); + bool modified(const Film &film); + void tag_passes_update(Scene *scene, const vector<Pass> &passes_); + void tag_update(Scene *scene); }; CCL_NAMESPACE_END -#endif /* __FILM_H__ */ +#endif /* __FILM_H__ */ diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index eea1bed58dc..c284c64b5bf 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -33,388 +33,385 @@ namespace { bool check_node_inputs_has_links(const ShaderNode *node) { - foreach(const ShaderInput *in, node->inputs) { - if(in->link) { - return true; - } - } - return false; + foreach (const ShaderInput *in, node->inputs) { + if (in->link) { + return true; + } + } + return false; } -bool check_node_inputs_traversed(const ShaderNode *node, - const ShaderNodeSet& done) +bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &done) { - foreach(const ShaderInput *in, node->inputs) { - if(in->link) { - if(done.find(in->link->parent) == done.end()) { - return false; - } - } - } - return true; + foreach (const ShaderInput *in, node->inputs) { + if (in->link) { + if (done.find(in->link->parent) == done.end()) { + return false; + } + } + } + return true; } -} /* namespace */ +} /* namespace */ /* Node */ -ShaderNode::ShaderNode(const NodeType *type) -: Node(type) +ShaderNode::ShaderNode(const NodeType *type) : Node(type) { - name = type->name; - id = -1; - bump = SHADER_BUMP_NONE; - special_type = SHADER_SPECIAL_TYPE_NONE; + name = type->name; + id = -1; + bump = SHADER_BUMP_NONE; + special_type = SHADER_SPECIAL_TYPE_NONE; - create_inputs_outputs(type); + create_inputs_outputs(type); } ShaderNode::~ShaderNode() { - foreach(ShaderInput *socket, inputs) - delete socket; + foreach (ShaderInput *socket, inputs) + delete socket; - foreach(ShaderOutput *socket, outputs) - delete socket; + foreach (ShaderOutput *socket, outputs) + delete socket; } void ShaderNode::create_inputs_outputs(const NodeType *type) { - foreach(const SocketType& socket, type->inputs) { - if(socket.flags & SocketType::LINKABLE) { - inputs.push_back(new ShaderInput(socket, this)); - } - } - - foreach(const SocketType& socket, type->outputs) { - outputs.push_back(new ShaderOutput(socket, this)); - } + foreach (const SocketType &socket, type->inputs) { + if (socket.flags & SocketType::LINKABLE) { + inputs.push_back(new ShaderInput(socket, this)); + } + } + + foreach (const SocketType &socket, type->outputs) { + outputs.push_back(new ShaderOutput(socket, this)); + } } ShaderInput *ShaderNode::input(const char *name) { - foreach(ShaderInput *socket, inputs) { - if(socket->name() == name) - return socket; - } + foreach (ShaderInput *socket, inputs) { + if (socket->name() == name) + return socket; + } - return NULL; + return NULL; } ShaderOutput *ShaderNode::output(const char *name) { - foreach(ShaderOutput *socket, outputs) - if(socket->name() == name) - return socket; + foreach (ShaderOutput *socket, outputs) + if (socket->name() == name) + return socket; - return NULL; + return NULL; } ShaderInput *ShaderNode::input(ustring name) { - foreach(ShaderInput *socket, inputs) { - if(socket->name() == name) - return socket; - } + foreach (ShaderInput *socket, inputs) { + if (socket->name() == name) + return socket; + } - return NULL; + return NULL; } ShaderOutput *ShaderNode::output(ustring name) { - foreach(ShaderOutput *socket, outputs) - if(socket->name() == name) - return socket; + foreach (ShaderOutput *socket, outputs) + if (socket->name() == name) + return socket; - return NULL; + return NULL; } void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - foreach(ShaderInput *input, inputs) { - if(!input->link) { - if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) { - if(shader->has_surface) - attributes->add(ATTR_STD_GENERATED); - if(shader->has_volume) - attributes->add(ATTR_STD_GENERATED_TRANSFORM); - } - else if(input->flags() & SocketType::LINK_TEXTURE_UV) { - if(shader->has_surface) - attributes->add(ATTR_STD_UV); - } - } - } + foreach (ShaderInput *input, inputs) { + if (!input->link) { + if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) { + if (shader->has_surface) + attributes->add(ATTR_STD_GENERATED); + if (shader->has_volume) + attributes->add(ATTR_STD_GENERATED_TRANSFORM); + } + else if (input->flags() & SocketType::LINK_TEXTURE_UV) { + if (shader->has_surface) + attributes->add(ATTR_STD_UV); + } + } + } } -bool ShaderNode::equals(const ShaderNode& other) +bool ShaderNode::equals(const ShaderNode &other) { - if(type != other.type || bump != other.bump) { - return false; - } - - assert(inputs.size() == other.inputs.size()); - - /* Compare unlinkable sockets */ - foreach(const SocketType& socket, type->inputs) { - if(!(socket.flags & SocketType::LINKABLE)) { - if(!Node::equals_value(other, socket)) { - return false; - } - } - } - - /* Compare linkable input sockets */ - for(int i = 0; i < inputs.size(); ++i) { - ShaderInput *input_a = inputs[i], - *input_b = other.inputs[i]; - if(input_a->link == NULL && input_b->link == NULL) { - /* Unconnected inputs are expected to have the same value. */ - if(!Node::equals_value(other, input_a->socket_type)) { - return false; - } - } - else if(input_a->link != NULL && input_b->link != NULL) { - /* Expect links are to come from the same exact socket. */ - if(input_a->link != input_b->link) { - return false; - } - } - else { - /* One socket has a link and another has not, inputs can't be - * considered equal. - */ - return false; - } - } - - return true; + if (type != other.type || bump != other.bump) { + return false; + } + + assert(inputs.size() == other.inputs.size()); + + /* Compare unlinkable sockets */ + foreach (const SocketType &socket, type->inputs) { + if (!(socket.flags & SocketType::LINKABLE)) { + if (!Node::equals_value(other, socket)) { + return false; + } + } + } + + /* Compare linkable input sockets */ + for (int i = 0; i < inputs.size(); ++i) { + ShaderInput *input_a = inputs[i], *input_b = other.inputs[i]; + if (input_a->link == NULL && input_b->link == NULL) { + /* Unconnected inputs are expected to have the same value. */ + if (!Node::equals_value(other, input_a->socket_type)) { + return false; + } + } + else if (input_a->link != NULL && input_b->link != NULL) { + /* Expect links are to come from the same exact socket. */ + if (input_a->link != input_b->link) { + return false; + } + } + else { + /* One socket has a link and another has not, inputs can't be + * considered equal. + */ + return false; + } + } + + return true; } /* Graph */ ShaderGraph::ShaderGraph() { - finalized = false; - simplified = false; - num_node_ids = 0; - add(new OutputNode()); + finalized = false; + simplified = false; + num_node_ids = 0; + add(new OutputNode()); } ShaderGraph::~ShaderGraph() { - clear_nodes(); + clear_nodes(); } ShaderNode *ShaderGraph::add(ShaderNode *node) { - assert(!finalized); - simplified = false; + assert(!finalized); + simplified = false; - node->id = num_node_ids++; - nodes.push_back(node); - return node; + node->id = num_node_ids++; + nodes.push_back(node); + return node; } OutputNode *ShaderGraph::output() { - return (OutputNode*)nodes.front(); + return (OutputNode *)nodes.front(); } void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) { - assert(!finalized); - assert(from && to); - - if(to->link) { - fprintf(stderr, "Cycles shader graph connect: input already connected.\n"); - return; - } - - if(from->type() != to->type()) { - /* can't do automatic conversion from closure */ - if(from->type() == SocketType::CLOSURE) { - fprintf(stderr, "Cycles shader graph connect: can only connect closure to closure " - "(%s.%s to %s.%s).\n", - from->parent->name.c_str(), from->name().c_str(), - to->parent->name.c_str(), to->name().c_str()); - return; - } - - /* add automatic conversion node in case of type mismatch */ - ShaderNode *convert; - ShaderInput *convert_in; - - if(to->type() == SocketType::CLOSURE) { - EmissionNode *emission = new EmissionNode(); - emission->color = make_float3(1.0f, 1.0f, 1.0f); - emission->strength = 1.0f; - convert = add(emission); - /* Connect float inputs to Strength to save an additional Falue->Color conversion. */ - if(from->type() == SocketType::FLOAT) { - convert_in = convert->input("Strength"); - } - else { - convert_in = convert->input("Color"); - } - } - else { - convert = add(new ConvertNode(from->type(), to->type(), true)); - convert_in = convert->inputs[0]; - } - - connect(from, convert_in); - connect(convert->outputs[0], to); - } - else { - /* types match, just connect */ - to->link = from; - from->links.push_back(to); - } + assert(!finalized); + assert(from && to); + + if (to->link) { + fprintf(stderr, "Cycles shader graph connect: input already connected.\n"); + return; + } + + if (from->type() != to->type()) { + /* can't do automatic conversion from closure */ + if (from->type() == SocketType::CLOSURE) { + fprintf(stderr, + "Cycles shader graph connect: can only connect closure to closure " + "(%s.%s to %s.%s).\n", + from->parent->name.c_str(), + from->name().c_str(), + to->parent->name.c_str(), + to->name().c_str()); + return; + } + + /* add automatic conversion node in case of type mismatch */ + ShaderNode *convert; + ShaderInput *convert_in; + + if (to->type() == SocketType::CLOSURE) { + EmissionNode *emission = new EmissionNode(); + emission->color = make_float3(1.0f, 1.0f, 1.0f); + emission->strength = 1.0f; + convert = add(emission); + /* Connect float inputs to Strength to save an additional Falue->Color conversion. */ + if (from->type() == SocketType::FLOAT) { + convert_in = convert->input("Strength"); + } + else { + convert_in = convert->input("Color"); + } + } + else { + convert = add(new ConvertNode(from->type(), to->type(), true)); + convert_in = convert->inputs[0]; + } + + connect(from, convert_in); + connect(convert->outputs[0], to); + } + else { + /* types match, just connect */ + to->link = from; + from->links.push_back(to); + } } void ShaderGraph::disconnect(ShaderOutput *from) { - assert(!finalized); - simplified = false; + assert(!finalized); + simplified = false; - foreach(ShaderInput *sock, from->links) { - sock->link = NULL; - } + foreach (ShaderInput *sock, from->links) { + sock->link = NULL; + } - from->links.clear(); + from->links.clear(); } void ShaderGraph::disconnect(ShaderInput *to) { - assert(!finalized); - assert(to->link); - simplified = false; + assert(!finalized); + assert(to->link); + simplified = false; - ShaderOutput *from = to->link; + ShaderOutput *from = to->link; - to->link = NULL; - from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); + to->link = NULL; + from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); } void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to) { - simplified = false; - - /* Copy because disconnect modifies this list */ - vector<ShaderInput*> outputs = from->links; - - /* Bypass node by moving all links from "from" to "to" */ - foreach(ShaderInput *sock, node->inputs) { - if(sock->link) - disconnect(sock); - } - - foreach(ShaderInput *sock, outputs) { - disconnect(sock); - if(to) - connect(to, sock); - } + simplified = false; + + /* Copy because disconnect modifies this list */ + vector<ShaderInput *> outputs = from->links; + + /* Bypass node by moving all links from "from" to "to" */ + foreach (ShaderInput *sock, node->inputs) { + if (sock->link) + disconnect(sock); + } + + foreach (ShaderInput *sock, outputs) { + disconnect(sock); + if (to) + connect(to, sock); + } } void ShaderGraph::simplify(Scene *scene) { - if(!simplified) { - default_inputs(scene->shader_manager->use_osl()); - clean(scene); - refine_bump_nodes(); + if (!simplified) { + default_inputs(scene->shader_manager->use_osl()); + clean(scene); + refine_bump_nodes(); - simplified = true; - } + simplified = true; + } } -void ShaderGraph::finalize(Scene *scene, - bool do_bump, - bool do_simplify, - bool bump_in_object_space) +void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bump_in_object_space) { - /* before compiling, the shader graph may undergo a number of modifications. - * currently we set default geometry shader inputs, and create automatic bump - * from displacement. a graph can be finalized only once, and should not be - * modified afterwards. */ + /* before compiling, the shader graph may undergo a number of modifications. + * currently we set default geometry shader inputs, and create automatic bump + * from displacement. a graph can be finalized only once, and should not be + * modified afterwards. */ - if(!finalized) { - simplify(scene); + if (!finalized) { + simplify(scene); - if(do_bump) - bump_from_displacement(bump_in_object_space); + if (do_bump) + bump_from_displacement(bump_in_object_space); - ShaderInput *surface_in = output()->input("Surface"); - ShaderInput *volume_in = output()->input("Volume"); + ShaderInput *surface_in = output()->input("Surface"); + ShaderInput *volume_in = output()->input("Volume"); - /* todo: make this work when surface and volume closures are tangled up */ + /* todo: make this work when surface and volume closures are tangled up */ - if(surface_in->link) - transform_multi_closure(surface_in->link->parent, NULL, false); - if(volume_in->link) - transform_multi_closure(volume_in->link->parent, NULL, true); + if (surface_in->link) + transform_multi_closure(surface_in->link->parent, NULL, false); + if (volume_in->link) + transform_multi_closure(volume_in->link->parent, NULL, true); - finalized = true; - } - else if(do_simplify) { - simplify_settings(scene); - } + finalized = true; + } + else if (do_simplify) { + simplify_settings(scene); + } } -void ShaderGraph::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input) +void ShaderGraph::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input) { - /* find all nodes that this input depends on directly and indirectly */ - ShaderNode *node = (input->link)? input->link->parent: NULL; + /* find all nodes that this input depends on directly and indirectly */ + ShaderNode *node = (input->link) ? input->link->parent : NULL; - if(node != NULL && dependencies.find(node) == dependencies.end()) { - foreach(ShaderInput *in, node->inputs) - find_dependencies(dependencies, in); + if (node != NULL && dependencies.find(node) == dependencies.end()) { + foreach (ShaderInput *in, node->inputs) + find_dependencies(dependencies, in); - dependencies.insert(node); - } + dependencies.insert(node); + } } void ShaderGraph::clear_nodes() { - foreach(ShaderNode *node, nodes) { - delete node; - } - nodes.clear(); + foreach (ShaderNode *node, nodes) { + delete node; + } + nodes.clear(); } -void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap) +void ShaderGraph::copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap) { - /* copy a set of nodes, and the links between them. the assumption is - * made that all nodes that inputs are linked to are in the set too. */ - - /* copy nodes */ - foreach(ShaderNode *node, nodes) { - ShaderNode *nnode = node->clone(); - nnodemap[node] = nnode; - - /* create new inputs and outputs to recreate links and ensure - * that we still point to valid SocketType if the NodeType - * changed in cloning, as it does for OSL nodes */ - nnode->inputs.clear(); - nnode->outputs.clear(); - nnode->create_inputs_outputs(nnode->type); - } - - /* recreate links */ - foreach(ShaderNode *node, nodes) { - foreach(ShaderInput *input, node->inputs) { - if(input->link) { - /* find new input and output */ - ShaderNode *nfrom = nnodemap[input->link->parent]; - ShaderNode *nto = nnodemap[input->parent]; - ShaderOutput *noutput = nfrom->output(input->link->name()); - ShaderInput *ninput = nto->input(input->name()); - - /* connect */ - connect(noutput, ninput); - } - } - } + /* copy a set of nodes, and the links between them. the assumption is + * made that all nodes that inputs are linked to are in the set too. */ + + /* copy nodes */ + foreach (ShaderNode *node, nodes) { + ShaderNode *nnode = node->clone(); + nnodemap[node] = nnode; + + /* create new inputs and outputs to recreate links and ensure + * that we still point to valid SocketType if the NodeType + * changed in cloning, as it does for OSL nodes */ + nnode->inputs.clear(); + nnode->outputs.clear(); + nnode->create_inputs_outputs(nnode->type); + } + + /* recreate links */ + foreach (ShaderNode *node, nodes) { + foreach (ShaderInput *input, node->inputs) { + if (input->link) { + /* find new input and output */ + ShaderNode *nfrom = nnodemap[input->link->parent]; + ShaderNode *nto = nnodemap[input->parent]; + ShaderOutput *noutput = nfrom->output(input->link->name()); + ShaderInput *ninput = nto->input(input->name()); + + /* connect */ + connect(noutput, ninput); + } + } + } } /* Graph simplification */ @@ -427,68 +424,68 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap) */ void ShaderGraph::remove_proxy_nodes() { - vector<bool> removed(num_node_ids, false); - bool any_node_removed = false; - - foreach(ShaderNode *node, nodes) { - if(node->special_type == SHADER_SPECIAL_TYPE_PROXY) { - ConvertNode *proxy = static_cast<ConvertNode*>(node); - ShaderInput *input = proxy->inputs[0]; - ShaderOutput *output = proxy->outputs[0]; - - /* bypass the proxy node */ - if(input->link) { - relink(proxy, output, input->link); - } - else { - /* Copy because disconnect modifies this list */ - vector<ShaderInput*> links(output->links); - - foreach(ShaderInput *to, links) { - /* remove any autoconvert nodes too if they lead to - * sockets with an automatically set default value */ - ShaderNode *tonode = to->parent; - - if(tonode->special_type == SHADER_SPECIAL_TYPE_AUTOCONVERT) { - bool all_links_removed = true; - vector<ShaderInput*> links = tonode->outputs[0]->links; - - foreach(ShaderInput *autoin, links) { - if(autoin->flags() & SocketType::DEFAULT_LINK_MASK) - disconnect(autoin); - else - all_links_removed = false; - } - - if(all_links_removed) - removed[tonode->id] = true; - } - - disconnect(to); - - /* transfer the default input value to the target socket */ - tonode->copy_value(to->socket_type, *proxy, input->socket_type); - } - } - - removed[proxy->id] = true; - any_node_removed = true; - } - } - - /* remove nodes */ - if(any_node_removed) { - list<ShaderNode*> newnodes; - - foreach(ShaderNode *node, nodes) { - if(!removed[node->id]) - newnodes.push_back(node); - else - delete node; - } - - nodes = newnodes; - } + vector<bool> removed(num_node_ids, false); + bool any_node_removed = false; + + foreach (ShaderNode *node, nodes) { + if (node->special_type == SHADER_SPECIAL_TYPE_PROXY) { + ConvertNode *proxy = static_cast<ConvertNode *>(node); + ShaderInput *input = proxy->inputs[0]; + ShaderOutput *output = proxy->outputs[0]; + + /* bypass the proxy node */ + if (input->link) { + relink(proxy, output, input->link); + } + else { + /* Copy because disconnect modifies this list */ + vector<ShaderInput *> links(output->links); + + foreach (ShaderInput *to, links) { + /* remove any autoconvert nodes too if they lead to + * sockets with an automatically set default value */ + ShaderNode *tonode = to->parent; + + if (tonode->special_type == SHADER_SPECIAL_TYPE_AUTOCONVERT) { + bool all_links_removed = true; + vector<ShaderInput *> links = tonode->outputs[0]->links; + + foreach (ShaderInput *autoin, links) { + if (autoin->flags() & SocketType::DEFAULT_LINK_MASK) + disconnect(autoin); + else + all_links_removed = false; + } + + if (all_links_removed) + removed[tonode->id] = true; + } + + disconnect(to); + + /* transfer the default input value to the target socket */ + tonode->copy_value(to->socket_type, *proxy, input->socket_type); + } + } + + removed[proxy->id] = true; + any_node_removed = true; + } + } + + /* remove nodes */ + if (any_node_removed) { + list<ShaderNode *> newnodes; + + foreach (ShaderNode *node, nodes) { + if (!removed[node->id]) + newnodes.push_back(node); + else + delete node; + } + + nodes = newnodes; + } } /* Constant folding. @@ -498,143 +495,143 @@ void ShaderGraph::remove_proxy_nodes() */ void ShaderGraph::constant_fold(Scene *scene) { - ShaderNodeSet done, scheduled; - queue<ShaderNode*> traverse_queue; - - bool has_displacement = (output()->input("Displacement")->link != NULL); - - /* Schedule nodes which doesn't have any dependencies. */ - foreach(ShaderNode *node, nodes) { - if(!check_node_inputs_has_links(node)) { - traverse_queue.push(node); - scheduled.insert(node); - } - } - - while(!traverse_queue.empty()) { - ShaderNode *node = traverse_queue.front(); - traverse_queue.pop(); - done.insert(node); - foreach(ShaderOutput *output, node->outputs) { - if(output->links.size() == 0) { - continue; - } - /* Schedule node which was depending on the value, - * when possible. Do it before disconnect. - */ - foreach(ShaderInput *input, output->links) { - if(scheduled.find(input->parent) != scheduled.end()) { - /* Node might not be optimized yet but scheduled already - * by other dependencies. No need to re-schedule it. - */ - continue; - } - /* Schedule node if its inputs are fully done. */ - if(check_node_inputs_traversed(input->parent, done)) { - traverse_queue.push(input->parent); - scheduled.insert(input->parent); - } - } - /* Optimize current node. */ - ConstantFolder folder(this, node, output, scene); - node->constant_fold(folder); - } - } - - /* Folding might have removed all nodes connected to the displacement output - * even tho there is displacement to be applied, so add in a value node if - * that happens to ensure there is still a valid graph for displacement. - */ - if(has_displacement && !output()->input("Displacement")->link) { - ColorNode *value = (ColorNode*)add(new ColorNode()); - value->value = output()->displacement; - - connect(value->output("Color"), output()->input("Displacement")); - } + ShaderNodeSet done, scheduled; + queue<ShaderNode *> traverse_queue; + + bool has_displacement = (output()->input("Displacement")->link != NULL); + + /* Schedule nodes which doesn't have any dependencies. */ + foreach (ShaderNode *node, nodes) { + if (!check_node_inputs_has_links(node)) { + traverse_queue.push(node); + scheduled.insert(node); + } + } + + while (!traverse_queue.empty()) { + ShaderNode *node = traverse_queue.front(); + traverse_queue.pop(); + done.insert(node); + foreach (ShaderOutput *output, node->outputs) { + if (output->links.size() == 0) { + continue; + } + /* Schedule node which was depending on the value, + * when possible. Do it before disconnect. + */ + foreach (ShaderInput *input, output->links) { + if (scheduled.find(input->parent) != scheduled.end()) { + /* Node might not be optimized yet but scheduled already + * by other dependencies. No need to re-schedule it. + */ + continue; + } + /* Schedule node if its inputs are fully done. */ + if (check_node_inputs_traversed(input->parent, done)) { + traverse_queue.push(input->parent); + scheduled.insert(input->parent); + } + } + /* Optimize current node. */ + ConstantFolder folder(this, node, output, scene); + node->constant_fold(folder); + } + } + + /* Folding might have removed all nodes connected to the displacement output + * even tho there is displacement to be applied, so add in a value node if + * that happens to ensure there is still a valid graph for displacement. + */ + if (has_displacement && !output()->input("Displacement")->link) { + ColorNode *value = (ColorNode *)add(new ColorNode()); + value->value = output()->displacement; + + connect(value->output("Color"), output()->input("Displacement")); + } } /* Simplification. */ void ShaderGraph::simplify_settings(Scene *scene) { - foreach(ShaderNode *node, nodes) { - node->simplify_settings(scene); - } + foreach (ShaderNode *node, nodes) { + node->simplify_settings(scene); + } } /* Deduplicate nodes with same settings. */ void ShaderGraph::deduplicate_nodes() { - /* NOTES: - * - Deduplication happens for nodes which has same exact settings and same - * exact input links configuration (either connected to same output or has - * the same exact default value). - * - Deduplication happens in the bottom-top manner, so we know for fact that - * all traversed nodes are either can not be deduplicated at all or were - * already deduplicated. - */ - - ShaderNodeSet scheduled, done; - map<ustring, ShaderNodeSet> candidates; - queue<ShaderNode*> traverse_queue; - int num_deduplicated = 0; - - /* Schedule nodes which doesn't have any dependencies. */ - foreach(ShaderNode *node, nodes) { - if(!check_node_inputs_has_links(node)) { - traverse_queue.push(node); - scheduled.insert(node); - } - } - - while(!traverse_queue.empty()) { - ShaderNode *node = traverse_queue.front(); - traverse_queue.pop(); - done.insert(node); - /* Schedule the nodes which were depending on the current node. */ - bool has_output_links = false; - foreach(ShaderOutput *output, node->outputs) { - foreach(ShaderInput *input, output->links) { - has_output_links = true; - if(scheduled.find(input->parent) != scheduled.end()) { - /* Node might not be optimized yet but scheduled already - * by other dependencies. No need to re-schedule it. - */ - continue; - } - /* Schedule node if its inputs are fully done. */ - if(check_node_inputs_traversed(input->parent, done)) { - traverse_queue.push(input->parent); - scheduled.insert(input->parent); - } - } - } - /* Only need to care about nodes that are actually used */ - if(!has_output_links) { - continue; - } - /* Try to merge this node with another one. */ - ShaderNode *merge_with = NULL; - foreach(ShaderNode *other_node, candidates[node->type->name]) { - if(node != other_node && node->equals(*other_node)) { - merge_with = other_node; - break; - } - } - /* If found an equivalent, merge; otherwise keep node for later merges */ - if(merge_with != NULL) { - for(int i = 0; i < node->outputs.size(); ++i) { - relink(node, node->outputs[i], merge_with->outputs[i]); - } - num_deduplicated++; - } - else { - candidates[node->type->name].insert(node); - } - } - - if(num_deduplicated > 0) { - VLOG(1) << "Deduplicated " << num_deduplicated << " nodes."; - } + /* NOTES: + * - Deduplication happens for nodes which has same exact settings and same + * exact input links configuration (either connected to same output or has + * the same exact default value). + * - Deduplication happens in the bottom-top manner, so we know for fact that + * all traversed nodes are either can not be deduplicated at all or were + * already deduplicated. + */ + + ShaderNodeSet scheduled, done; + map<ustring, ShaderNodeSet> candidates; + queue<ShaderNode *> traverse_queue; + int num_deduplicated = 0; + + /* Schedule nodes which doesn't have any dependencies. */ + foreach (ShaderNode *node, nodes) { + if (!check_node_inputs_has_links(node)) { + traverse_queue.push(node); + scheduled.insert(node); + } + } + + while (!traverse_queue.empty()) { + ShaderNode *node = traverse_queue.front(); + traverse_queue.pop(); + done.insert(node); + /* Schedule the nodes which were depending on the current node. */ + bool has_output_links = false; + foreach (ShaderOutput *output, node->outputs) { + foreach (ShaderInput *input, output->links) { + has_output_links = true; + if (scheduled.find(input->parent) != scheduled.end()) { + /* Node might not be optimized yet but scheduled already + * by other dependencies. No need to re-schedule it. + */ + continue; + } + /* Schedule node if its inputs are fully done. */ + if (check_node_inputs_traversed(input->parent, done)) { + traverse_queue.push(input->parent); + scheduled.insert(input->parent); + } + } + } + /* Only need to care about nodes that are actually used */ + if (!has_output_links) { + continue; + } + /* Try to merge this node with another one. */ + ShaderNode *merge_with = NULL; + foreach (ShaderNode *other_node, candidates[node->type->name]) { + if (node != other_node && node->equals(*other_node)) { + merge_with = other_node; + break; + } + } + /* If found an equivalent, merge; otherwise keep node for later merges */ + if (merge_with != NULL) { + for (int i = 0; i < node->outputs.size(); ++i) { + relink(node, node->outputs[i], merge_with->outputs[i]); + } + num_deduplicated++; + } + else { + candidates[node->type->name].insert(node); + } + } + + if (num_deduplicated > 0) { + VLOG(1) << "Deduplicated " << num_deduplicated << " nodes."; + } } /* Check whether volume output has meaningful nodes, otherwise @@ -642,535 +639,536 @@ void ShaderGraph::deduplicate_nodes() */ void ShaderGraph::verify_volume_output() { - /* Check whether we can optimize the whole volume graph out. */ - ShaderInput *volume_in = output()->input("Volume"); - if(volume_in->link == NULL) { - return; - } - bool has_valid_volume = false; - ShaderNodeSet scheduled; - queue<ShaderNode*> traverse_queue; - /* Schedule volume output. */ - traverse_queue.push(volume_in->link->parent); - scheduled.insert(volume_in->link->parent); - /* Traverse down the tree. */ - while(!traverse_queue.empty()) { - ShaderNode *node = traverse_queue.front(); - traverse_queue.pop(); - /* Node is fully valid for volume, can't optimize anything out. */ - if(node->has_volume_support()) { - has_valid_volume = true; - break; - } - foreach(ShaderInput *input, node->inputs) { - if(input->link == NULL) { - continue; - } - if(scheduled.find(input->link->parent) != scheduled.end()) { - continue; - } - traverse_queue.push(input->link->parent); - scheduled.insert(input->link->parent); - } - } - if(!has_valid_volume) { - VLOG(1) << "Disconnect meaningless volume output."; - disconnect(volume_in->link); - } + /* Check whether we can optimize the whole volume graph out. */ + ShaderInput *volume_in = output()->input("Volume"); + if (volume_in->link == NULL) { + return; + } + bool has_valid_volume = false; + ShaderNodeSet scheduled; + queue<ShaderNode *> traverse_queue; + /* Schedule volume output. */ + traverse_queue.push(volume_in->link->parent); + scheduled.insert(volume_in->link->parent); + /* Traverse down the tree. */ + while (!traverse_queue.empty()) { + ShaderNode *node = traverse_queue.front(); + traverse_queue.pop(); + /* Node is fully valid for volume, can't optimize anything out. */ + if (node->has_volume_support()) { + has_valid_volume = true; + break; + } + foreach (ShaderInput *input, node->inputs) { + if (input->link == NULL) { + continue; + } + if (scheduled.find(input->link->parent) != scheduled.end()) { + continue; + } + traverse_queue.push(input->link->parent); + scheduled.insert(input->link->parent); + } + } + if (!has_valid_volume) { + VLOG(1) << "Disconnect meaningless volume output."; + disconnect(volume_in->link); + } } -void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack) +void ShaderGraph::break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack) { - visited[node->id] = true; - on_stack[node->id] = true; - - foreach(ShaderInput *input, node->inputs) { - if(input->link) { - ShaderNode *depnode = input->link->parent; - - if(on_stack[depnode->id]) { - /* break cycle */ - disconnect(input); - fprintf(stderr, "Cycles shader graph: detected cycle in graph, connection removed.\n"); - } - else if(!visited[depnode->id]) { - /* visit dependencies */ - break_cycles(depnode, visited, on_stack); - } - } - } - - on_stack[node->id] = false; + visited[node->id] = true; + on_stack[node->id] = true; + + foreach (ShaderInput *input, node->inputs) { + if (input->link) { + ShaderNode *depnode = input->link->parent; + + if (on_stack[depnode->id]) { + /* break cycle */ + disconnect(input); + fprintf(stderr, "Cycles shader graph: detected cycle in graph, connection removed.\n"); + } + else if (!visited[depnode->id]) { + /* visit dependencies */ + break_cycles(depnode, visited, on_stack); + } + } + } + + on_stack[node->id] = false; } void ShaderGraph::compute_displacement_hash() { - /* Compute hash of all nodes linked to displacement, to detect if we need - * to recompute displacement when shader nodes change. */ - ShaderInput *displacement_in = output()->input("Displacement"); - - if(!displacement_in->link) { - displacement_hash = ""; - return; - } - - ShaderNodeSet nodes_displace; - find_dependencies(nodes_displace, displacement_in); - - MD5Hash md5; - foreach(ShaderNode *node, nodes_displace) { - node->hash(md5); - foreach(ShaderInput *input, node->inputs) { - int link_id = (input->link) ? input->link->parent->id : 0; - md5.append((uint8_t*)&link_id, sizeof(link_id)); - } - } - - displacement_hash = md5.get_hex(); + /* Compute hash of all nodes linked to displacement, to detect if we need + * to recompute displacement when shader nodes change. */ + ShaderInput *displacement_in = output()->input("Displacement"); + + if (!displacement_in->link) { + displacement_hash = ""; + return; + } + + ShaderNodeSet nodes_displace; + find_dependencies(nodes_displace, displacement_in); + + MD5Hash md5; + foreach (ShaderNode *node, nodes_displace) { + node->hash(md5); + foreach (ShaderInput *input, node->inputs) { + int link_id = (input->link) ? input->link->parent->id : 0; + md5.append((uint8_t *)&link_id, sizeof(link_id)); + } + } + + displacement_hash = md5.get_hex(); } void ShaderGraph::clean(Scene *scene) { - /* Graph simplification */ - - /* NOTE: Remove proxy nodes was already done. */ - constant_fold(scene); - simplify_settings(scene); - deduplicate_nodes(); - verify_volume_output(); - - /* we do two things here: find cycles and break them, and remove unused - * nodes that don't feed into the output. how cycles are broken is - * undefined, they are invalid input, the important thing is to not crash */ - - vector<bool> visited(num_node_ids, false); - vector<bool> on_stack(num_node_ids, false); - - /* break cycles */ - break_cycles(output(), visited, on_stack); - - /* disconnect unused nodes */ - foreach(ShaderNode *node, nodes) { - if(!visited[node->id]) { - foreach(ShaderInput *to, node->inputs) { - ShaderOutput *from = to->link; - - if(from) { - to->link = NULL; - from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); - } - } - } - } - - /* remove unused nodes */ - list<ShaderNode*> newnodes; - - foreach(ShaderNode *node, nodes) { - if(visited[node->id]) - newnodes.push_back(node); - else - delete node; - } - - nodes = newnodes; + /* Graph simplification */ + + /* NOTE: Remove proxy nodes was already done. */ + constant_fold(scene); + simplify_settings(scene); + deduplicate_nodes(); + verify_volume_output(); + + /* we do two things here: find cycles and break them, and remove unused + * nodes that don't feed into the output. how cycles are broken is + * undefined, they are invalid input, the important thing is to not crash */ + + vector<bool> visited(num_node_ids, false); + vector<bool> on_stack(num_node_ids, false); + + /* break cycles */ + break_cycles(output(), visited, on_stack); + + /* disconnect unused nodes */ + foreach (ShaderNode *node, nodes) { + if (!visited[node->id]) { + foreach (ShaderInput *to, node->inputs) { + ShaderOutput *from = to->link; + + if (from) { + to->link = NULL; + from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); + } + } + } + } + + /* remove unused nodes */ + list<ShaderNode *> newnodes; + + foreach (ShaderNode *node, nodes) { + if (visited[node->id]) + newnodes.push_back(node); + else + delete node; + } + + nodes = newnodes; } void ShaderGraph::default_inputs(bool do_osl) { - /* nodes can specify default texture coordinates, for now we give - * everything the position by default, except for the sky texture */ - - ShaderNode *geom = NULL; - ShaderNode *texco = NULL; - - foreach(ShaderNode *node, nodes) { - foreach(ShaderInput *input, node->inputs) { - if(!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) { - if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) { - if(!texco) - texco = new TextureCoordinateNode(); - - connect(texco->output("Generated"), input); - } - if(input->flags() & SocketType::LINK_TEXTURE_NORMAL) { - if(!texco) - texco = new TextureCoordinateNode(); - - connect(texco->output("Normal"), input); - } - else if(input->flags() & SocketType::LINK_TEXTURE_UV) { - if(!texco) - texco = new TextureCoordinateNode(); - - connect(texco->output("UV"), input); - } - else if(input->flags() & SocketType::LINK_INCOMING) { - if(!geom) - geom = new GeometryNode(); - - connect(geom->output("Incoming"), input); - } - else if(input->flags() & SocketType::LINK_NORMAL) { - if(!geom) - geom = new GeometryNode(); - - connect(geom->output("Normal"), input); - } - else if(input->flags() & SocketType::LINK_POSITION) { - if(!geom) - geom = new GeometryNode(); - - connect(geom->output("Position"), input); - } - else if(input->flags() & SocketType::LINK_TANGENT) { - if(!geom) - geom = new GeometryNode(); - - connect(geom->output("Tangent"), input); - } - } - } - } - - if(geom) - add(geom); - if(texco) - add(texco); + /* nodes can specify default texture coordinates, for now we give + * everything the position by default, except for the sky texture */ + + ShaderNode *geom = NULL; + ShaderNode *texco = NULL; + + foreach (ShaderNode *node, nodes) { + foreach (ShaderInput *input, node->inputs) { + if (!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) { + if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) { + if (!texco) + texco = new TextureCoordinateNode(); + + connect(texco->output("Generated"), input); + } + if (input->flags() & SocketType::LINK_TEXTURE_NORMAL) { + if (!texco) + texco = new TextureCoordinateNode(); + + connect(texco->output("Normal"), input); + } + else if (input->flags() & SocketType::LINK_TEXTURE_UV) { + if (!texco) + texco = new TextureCoordinateNode(); + + connect(texco->output("UV"), input); + } + else if (input->flags() & SocketType::LINK_INCOMING) { + if (!geom) + geom = new GeometryNode(); + + connect(geom->output("Incoming"), input); + } + else if (input->flags() & SocketType::LINK_NORMAL) { + if (!geom) + geom = new GeometryNode(); + + connect(geom->output("Normal"), input); + } + else if (input->flags() & SocketType::LINK_POSITION) { + if (!geom) + geom = new GeometryNode(); + + connect(geom->output("Position"), input); + } + else if (input->flags() & SocketType::LINK_TANGENT) { + if (!geom) + geom = new GeometryNode(); + + connect(geom->output("Tangent"), input); + } + } + } + } + + if (geom) + add(geom); + if (texco) + add(texco); } void ShaderGraph::refine_bump_nodes() { - /* we transverse the node graph looking for bump nodes, when we find them, - * like in bump_from_displacement(), we copy the sub-graph defined from "bump" - * input to the inputs "center","dx" and "dy" What is in "bump" input is moved - * to "center" input. */ - - foreach(ShaderNode *node, nodes) { - if(node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) { - ShaderInput *bump_input = node->input("Height"); - ShaderNodeSet nodes_bump; - - /* make 2 extra copies of the subgraph defined in Bump input */ - ShaderNodeMap nodes_dx; - ShaderNodeMap nodes_dy; - - /* find dependencies for the given input */ - find_dependencies(nodes_bump, bump_input); - - copy_nodes(nodes_bump, nodes_dx); - copy_nodes(nodes_bump, nodes_dy); - - /* mark nodes to indicate they are use for bump computation, so - that any texture coordinates are shifted by dx/dy when sampling */ - foreach(ShaderNode *node, nodes_bump) - node->bump = SHADER_BUMP_CENTER; - foreach(NodePair& pair, nodes_dx) - pair.second->bump = SHADER_BUMP_DX; - foreach(NodePair& pair, nodes_dy) - pair.second->bump = SHADER_BUMP_DY; - - ShaderOutput *out = bump_input->link; - ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); - ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); - - connect(out_dx, node->input("SampleX")); - connect(out_dy, node->input("SampleY")); - - /* add generated nodes */ - foreach(NodePair& pair, nodes_dx) - add(pair.second); - foreach(NodePair& pair, nodes_dy) - add(pair.second); - - /* connect what is connected is bump to samplecenter input*/ - connect(out , node->input("SampleCenter")); - - /* bump input is just for connectivity purpose for the graph input, - * we re-connected this input to samplecenter, so lets disconnect it - * from bump input */ - disconnect(bump_input); - } - } + /* we transverse the node graph looking for bump nodes, when we find them, + * like in bump_from_displacement(), we copy the sub-graph defined from "bump" + * input to the inputs "center","dx" and "dy" What is in "bump" input is moved + * to "center" input. */ + + foreach (ShaderNode *node, nodes) { + if (node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) { + ShaderInput *bump_input = node->input("Height"); + ShaderNodeSet nodes_bump; + + /* make 2 extra copies of the subgraph defined in Bump input */ + ShaderNodeMap nodes_dx; + ShaderNodeMap nodes_dy; + + /* find dependencies for the given input */ + find_dependencies(nodes_bump, bump_input); + + copy_nodes(nodes_bump, nodes_dx); + copy_nodes(nodes_bump, nodes_dy); + + /* mark nodes to indicate they are use for bump computation, so + that any texture coordinates are shifted by dx/dy when sampling */ + foreach (ShaderNode *node, nodes_bump) + node->bump = SHADER_BUMP_CENTER; + foreach (NodePair &pair, nodes_dx) + pair.second->bump = SHADER_BUMP_DX; + foreach (NodePair &pair, nodes_dy) + pair.second->bump = SHADER_BUMP_DY; + + ShaderOutput *out = bump_input->link; + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); + + connect(out_dx, node->input("SampleX")); + connect(out_dy, node->input("SampleY")); + + /* add generated nodes */ + foreach (NodePair &pair, nodes_dx) + add(pair.second); + foreach (NodePair &pair, nodes_dy) + add(pair.second); + + /* connect what is connected is bump to samplecenter input*/ + connect(out, node->input("SampleCenter")); + + /* bump input is just for connectivity purpose for the graph input, + * we re-connected this input to samplecenter, so lets disconnect it + * from bump input */ + disconnect(bump_input); + } + } } void ShaderGraph::bump_from_displacement(bool use_object_space) { - /* generate bump mapping automatically from displacement. bump mapping is - * done using a 3-tap filter, computing the displacement at the center, - * and two other positions shifted by ray differentials. - * - * since the input to displacement is a node graph, we need to ensure that - * all texture coordinates use are shift by the ray differentials. for this - * reason we make 3 copies of the node subgraph defining the displacement, - * with each different geometry and texture coordinate nodes that generate - * different shifted coordinates. - * - * these 3 displacement values are then fed into the bump node, which will - * output the perturbed normal. */ - - ShaderInput *displacement_in = output()->input("Displacement"); - - if(!displacement_in->link) - return; - - /* find dependencies for the given input */ - ShaderNodeSet nodes_displace; - find_dependencies(nodes_displace, displacement_in); - - /* copy nodes for 3 bump samples */ - ShaderNodeMap nodes_center; - ShaderNodeMap nodes_dx; - ShaderNodeMap nodes_dy; - - copy_nodes(nodes_displace, nodes_center); - copy_nodes(nodes_displace, nodes_dx); - copy_nodes(nodes_displace, nodes_dy); - - /* mark nodes to indicate they are use for bump computation, so - * that any texture coordinates are shifted by dx/dy when sampling */ - foreach(NodePair& pair, nodes_center) - pair.second->bump = SHADER_BUMP_CENTER; - foreach(NodePair& pair, nodes_dx) - pair.second->bump = SHADER_BUMP_DX; - foreach(NodePair& pair, nodes_dy) - pair.second->bump = SHADER_BUMP_DY; - - /* add set normal node and connect the bump normal ouput to the set normal - * output, so it can finally set the shader normal, note we are only doing - * this for bump from displacement, this will be the only bump allowed to - * overwrite the shader normal */ - ShaderNode *set_normal = add(new SetNormalNode()); - - /* add bump node and connect copied graphs to it */ - BumpNode *bump = (BumpNode*)add(new BumpNode()); - bump->use_object_space = use_object_space; - bump->distance = 1.0f; - - ShaderOutput *out = displacement_in->link; - ShaderOutput *out_center = nodes_center[out->parent]->output(out->name()); - ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); - ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); - - /* convert displacement vector to height */ - VectorMathNode *dot_center = (VectorMathNode*)add(new VectorMathNode()); - VectorMathNode *dot_dx = (VectorMathNode*)add(new VectorMathNode()); - VectorMathNode *dot_dy = (VectorMathNode*)add(new VectorMathNode()); - - dot_center->type = NODE_VECTOR_MATH_DOT_PRODUCT; - dot_dx->type = NODE_VECTOR_MATH_DOT_PRODUCT; - dot_dy->type = NODE_VECTOR_MATH_DOT_PRODUCT; - - GeometryNode *geom = (GeometryNode*)add(new GeometryNode()); - connect(geom->output("Normal"), dot_center->input("Vector2")); - connect(geom->output("Normal"), dot_dx->input("Vector2")); - connect(geom->output("Normal"), dot_dy->input("Vector2")); - - connect(out_center, dot_center->input("Vector1")); - connect(out_dx, dot_dx->input("Vector1")); - connect(out_dy, dot_dy->input("Vector1")); - - connect(dot_center->output("Value"), bump->input("SampleCenter")); - connect(dot_dx->output("Value"), bump->input("SampleX")); - connect(dot_dy->output("Value"), bump->input("SampleY")); - - /* connect the bump out to the set normal in: */ - connect(bump->output("Normal"), set_normal->input("Direction")); - - /* connect to output node */ - connect(set_normal->output("Normal"), output()->input("Normal")); - - /* finally, add the copied nodes to the graph. we can't do this earlier - * because we would create dependency cycles in the above loop */ - foreach(NodePair& pair, nodes_center) - add(pair.second); - foreach(NodePair& pair, nodes_dx) - add(pair.second); - foreach(NodePair& pair, nodes_dy) - add(pair.second); + /* generate bump mapping automatically from displacement. bump mapping is + * done using a 3-tap filter, computing the displacement at the center, + * and two other positions shifted by ray differentials. + * + * since the input to displacement is a node graph, we need to ensure that + * all texture coordinates use are shift by the ray differentials. for this + * reason we make 3 copies of the node subgraph defining the displacement, + * with each different geometry and texture coordinate nodes that generate + * different shifted coordinates. + * + * these 3 displacement values are then fed into the bump node, which will + * output the perturbed normal. */ + + ShaderInput *displacement_in = output()->input("Displacement"); + + if (!displacement_in->link) + return; + + /* find dependencies for the given input */ + ShaderNodeSet nodes_displace; + find_dependencies(nodes_displace, displacement_in); + + /* copy nodes for 3 bump samples */ + ShaderNodeMap nodes_center; + ShaderNodeMap nodes_dx; + ShaderNodeMap nodes_dy; + + copy_nodes(nodes_displace, nodes_center); + copy_nodes(nodes_displace, nodes_dx); + copy_nodes(nodes_displace, nodes_dy); + + /* mark nodes to indicate they are use for bump computation, so + * that any texture coordinates are shifted by dx/dy when sampling */ + foreach (NodePair &pair, nodes_center) + pair.second->bump = SHADER_BUMP_CENTER; + foreach (NodePair &pair, nodes_dx) + pair.second->bump = SHADER_BUMP_DX; + foreach (NodePair &pair, nodes_dy) + pair.second->bump = SHADER_BUMP_DY; + + /* add set normal node and connect the bump normal ouput to the set normal + * output, so it can finally set the shader normal, note we are only doing + * this for bump from displacement, this will be the only bump allowed to + * overwrite the shader normal */ + ShaderNode *set_normal = add(new SetNormalNode()); + + /* add bump node and connect copied graphs to it */ + BumpNode *bump = (BumpNode *)add(new BumpNode()); + bump->use_object_space = use_object_space; + bump->distance = 1.0f; + + ShaderOutput *out = displacement_in->link; + ShaderOutput *out_center = nodes_center[out->parent]->output(out->name()); + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name()); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name()); + + /* convert displacement vector to height */ + VectorMathNode *dot_center = (VectorMathNode *)add(new VectorMathNode()); + VectorMathNode *dot_dx = (VectorMathNode *)add(new VectorMathNode()); + VectorMathNode *dot_dy = (VectorMathNode *)add(new VectorMathNode()); + + dot_center->type = NODE_VECTOR_MATH_DOT_PRODUCT; + dot_dx->type = NODE_VECTOR_MATH_DOT_PRODUCT; + dot_dy->type = NODE_VECTOR_MATH_DOT_PRODUCT; + + GeometryNode *geom = (GeometryNode *)add(new GeometryNode()); + connect(geom->output("Normal"), dot_center->input("Vector2")); + connect(geom->output("Normal"), dot_dx->input("Vector2")); + connect(geom->output("Normal"), dot_dy->input("Vector2")); + + connect(out_center, dot_center->input("Vector1")); + connect(out_dx, dot_dx->input("Vector1")); + connect(out_dy, dot_dy->input("Vector1")); + + connect(dot_center->output("Value"), bump->input("SampleCenter")); + connect(dot_dx->output("Value"), bump->input("SampleX")); + connect(dot_dy->output("Value"), bump->input("SampleY")); + + /* connect the bump out to the set normal in: */ + connect(bump->output("Normal"), set_normal->input("Direction")); + + /* connect to output node */ + connect(set_normal->output("Normal"), output()->input("Normal")); + + /* finally, add the copied nodes to the graph. we can't do this earlier + * because we would create dependency cycles in the above loop */ + foreach (NodePair &pair, nodes_center) + add(pair.second); + foreach (NodePair &pair, nodes_dx) + add(pair.second); + foreach (NodePair &pair, nodes_dy) + add(pair.second); } void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume) { - /* for SVM in multi closure mode, this transforms the shader mix/add part of - * the graph into nodes that feed weights into closure nodes. this is too - * avoid building a closure tree and then flattening it, and instead write it - * directly to an array */ - - if(node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) { - ShaderInput *fin = node->input("Fac"); - ShaderInput *cl1in = node->input("Closure1"); - ShaderInput *cl2in = node->input("Closure2"); - ShaderOutput *weight1_out, *weight2_out; - - if(fin) { - /* mix closure: add node to mix closure weights */ - MixClosureWeightNode *mix_node = new MixClosureWeightNode(); - add(mix_node); - ShaderInput *fac_in = mix_node->input("Fac"); - ShaderInput *weight_in = mix_node->input("Weight"); - - if(fin->link) - connect(fin->link, fac_in); - else - mix_node->fac = node->get_float(fin->socket_type); - - if(weight_out) - connect(weight_out, weight_in); - - weight1_out = mix_node->output("Weight1"); - weight2_out = mix_node->output("Weight2"); - } - else { - /* add closure: just pass on any weights */ - weight1_out = weight_out; - weight2_out = weight_out; - } - - if(cl1in->link) - transform_multi_closure(cl1in->link->parent, weight1_out, volume); - if(cl2in->link) - transform_multi_closure(cl2in->link->parent, weight2_out, volume); - } - else { - ShaderInput *weight_in = node->input((volume)? "VolumeMixWeight": "SurfaceMixWeight"); - - /* not a closure node? */ - if(!weight_in) - return; - - /* already has a weight connected to it? add weights */ - float weight_value = node->get_float(weight_in->socket_type); - if(weight_in->link || weight_value != 0.0f) { - MathNode *math_node = new MathNode(); - add(math_node); - - if(weight_in->link) - connect(weight_in->link, math_node->input("Value1")); - else - math_node->value1 = weight_value; - - if(weight_out) - connect(weight_out, math_node->input("Value2")); - else - math_node->value2 = 1.0f; - - weight_out = math_node->output("Value"); - if(weight_in->link) - disconnect(weight_in); - } - - /* connected to closure mix weight */ - if(weight_out) - connect(weight_out, weight_in); - else - node->set(weight_in->socket_type, weight_value + 1.0f); - } + /* for SVM in multi closure mode, this transforms the shader mix/add part of + * the graph into nodes that feed weights into closure nodes. this is too + * avoid building a closure tree and then flattening it, and instead write it + * directly to an array */ + + if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) { + ShaderInput *fin = node->input("Fac"); + ShaderInput *cl1in = node->input("Closure1"); + ShaderInput *cl2in = node->input("Closure2"); + ShaderOutput *weight1_out, *weight2_out; + + if (fin) { + /* mix closure: add node to mix closure weights */ + MixClosureWeightNode *mix_node = new MixClosureWeightNode(); + add(mix_node); + ShaderInput *fac_in = mix_node->input("Fac"); + ShaderInput *weight_in = mix_node->input("Weight"); + + if (fin->link) + connect(fin->link, fac_in); + else + mix_node->fac = node->get_float(fin->socket_type); + + if (weight_out) + connect(weight_out, weight_in); + + weight1_out = mix_node->output("Weight1"); + weight2_out = mix_node->output("Weight2"); + } + else { + /* add closure: just pass on any weights */ + weight1_out = weight_out; + weight2_out = weight_out; + } + + if (cl1in->link) + transform_multi_closure(cl1in->link->parent, weight1_out, volume); + if (cl2in->link) + transform_multi_closure(cl2in->link->parent, weight2_out, volume); + } + else { + ShaderInput *weight_in = node->input((volume) ? "VolumeMixWeight" : "SurfaceMixWeight"); + + /* not a closure node? */ + if (!weight_in) + return; + + /* already has a weight connected to it? add weights */ + float weight_value = node->get_float(weight_in->socket_type); + if (weight_in->link || weight_value != 0.0f) { + MathNode *math_node = new MathNode(); + add(math_node); + + if (weight_in->link) + connect(weight_in->link, math_node->input("Value1")); + else + math_node->value1 = weight_value; + + if (weight_out) + connect(weight_out, math_node->input("Value2")); + else + math_node->value2 = 1.0f; + + weight_out = math_node->output("Value"); + if (weight_in->link) + disconnect(weight_in); + } + + /* connected to closure mix weight */ + if (weight_out) + connect(weight_out, weight_in); + else + node->set(weight_in->socket_type, weight_value + 1.0f); + } } int ShaderGraph::get_num_closures() { - int num_closures = 0; - foreach(ShaderNode *node, nodes) { - ClosureType closure_type = node->get_closure_type(); - if(closure_type == CLOSURE_NONE_ID) { - continue; - } - else if(CLOSURE_IS_BSSRDF(closure_type)) { - num_closures += 3; - } - else if(CLOSURE_IS_GLASS(closure_type)) { - num_closures += 2; - } - else if(CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) { - num_closures += 2; - } - else if(CLOSURE_IS_PRINCIPLED(closure_type)) { - num_closures += 8; - } - else if(CLOSURE_IS_VOLUME(closure_type)) { - num_closures += VOLUME_STACK_SIZE; - } - else if(closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { - num_closures += 4; - } - else { - ++num_closures; - } - } - return num_closures; + int num_closures = 0; + foreach (ShaderNode *node, nodes) { + ClosureType closure_type = node->get_closure_type(); + if (closure_type == CLOSURE_NONE_ID) { + continue; + } + else if (CLOSURE_IS_BSSRDF(closure_type)) { + num_closures += 3; + } + else if (CLOSURE_IS_GLASS(closure_type)) { + num_closures += 2; + } + else if (CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) { + num_closures += 2; + } + else if (CLOSURE_IS_PRINCIPLED(closure_type)) { + num_closures += 8; + } + else if (CLOSURE_IS_VOLUME(closure_type)) { + num_closures += VOLUME_STACK_SIZE; + } + else if (closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { + num_closures += 4; + } + else { + ++num_closures; + } + } + return num_closures; } void ShaderGraph::dump_graph(const char *filename) { - FILE *fd = fopen(filename, "w"); - - if(fd == NULL) { - printf("Error opening file for dumping the graph: %s\n", filename); - return; - } - - fprintf(fd, "digraph shader_graph {\n"); - fprintf(fd, "ranksep=1.5\n"); - fprintf(fd, "rankdir=LR\n"); - fprintf(fd, "splines=false\n"); - - foreach(ShaderNode *node, nodes) { - fprintf(fd, "// NODE: %p\n", node); - fprintf(fd, "\"%p\" [shape=record,label=\"{", node); - if(node->inputs.size()) { - fprintf(fd, "{"); - foreach(ShaderInput *socket, node->inputs) { - if(socket != node->inputs[0]) { - fprintf(fd, "|"); - } - fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str()); - } - fprintf(fd, "}|"); - } - fprintf(fd, "%s", node->name.c_str()); - if(node->bump == SHADER_BUMP_CENTER) { - fprintf(fd, " (bump:center)"); - } - else if(node->bump == SHADER_BUMP_DX) { - fprintf(fd, " (bump:dx)"); - } - else if(node->bump == SHADER_BUMP_DY) { - fprintf(fd, " (bump:dy)"); - } - if(node->outputs.size()) { - fprintf(fd, "|{"); - foreach(ShaderOutput *socket, node->outputs) { - if(socket != node->outputs[0]) { - fprintf(fd, "|"); - } - fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str()); - } - fprintf(fd, "}"); - } - fprintf(fd, "}\"]"); - } - - foreach(ShaderNode *node, nodes) { - foreach(ShaderOutput *output, node->outputs) { - foreach(ShaderInput *input, output->links) { - fprintf(fd, - "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n", - output, - input, - output->name().c_str(), input->name().c_str()); - fprintf(fd, - "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n", - output->parent, - output, - input->parent, - input); - } - } - } - - fprintf(fd, "}\n"); - fclose(fd); + FILE *fd = fopen(filename, "w"); + + if (fd == NULL) { + printf("Error opening file for dumping the graph: %s\n", filename); + return; + } + + fprintf(fd, "digraph shader_graph {\n"); + fprintf(fd, "ranksep=1.5\n"); + fprintf(fd, "rankdir=LR\n"); + fprintf(fd, "splines=false\n"); + + foreach (ShaderNode *node, nodes) { + fprintf(fd, "// NODE: %p\n", node); + fprintf(fd, "\"%p\" [shape=record,label=\"{", node); + if (node->inputs.size()) { + fprintf(fd, "{"); + foreach (ShaderInput *socket, node->inputs) { + if (socket != node->inputs[0]) { + fprintf(fd, "|"); + } + fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str()); + } + fprintf(fd, "}|"); + } + fprintf(fd, "%s", node->name.c_str()); + if (node->bump == SHADER_BUMP_CENTER) { + fprintf(fd, " (bump:center)"); + } + else if (node->bump == SHADER_BUMP_DX) { + fprintf(fd, " (bump:dx)"); + } + else if (node->bump == SHADER_BUMP_DY) { + fprintf(fd, " (bump:dy)"); + } + if (node->outputs.size()) { + fprintf(fd, "|{"); + foreach (ShaderOutput *socket, node->outputs) { + if (socket != node->outputs[0]) { + fprintf(fd, "|"); + } + fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str()); + } + fprintf(fd, "}"); + } + fprintf(fd, "}\"]"); + } + + foreach (ShaderNode *node, nodes) { + foreach (ShaderOutput *output, node->outputs) { + foreach (ShaderInput *input, output->links) { + fprintf(fd, + "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n", + output, + input, + output->name().c_str(), + input->name().c_str()); + fprintf(fd, + "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n", + output->parent, + output, + input->parent, + input); + } + } + } + + fprintf(fd, "}\n"); + fclose(fd); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index d14a59b4900..a2c030fd226 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -49,12 +49,7 @@ class MD5Hash; * For bump mapping, a node may be evaluated multiple times, using different * samples to reconstruct the normal, this indicates the sample position */ -enum ShaderBump { - SHADER_BUMP_NONE, - SHADER_BUMP_CENTER, - SHADER_BUMP_DX, - SHADER_BUMP_DY -}; +enum ShaderBump { SHADER_BUMP_NONE, SHADER_BUMP_CENTER, SHADER_BUMP_DX, SHADER_BUMP_DY }; /* Identifiers for some special node types. * @@ -62,16 +57,16 @@ enum ShaderBump { * Cannot use dynamic_cast, as this is disabled for OSL. */ enum ShaderNodeSpecialType { - SHADER_SPECIAL_TYPE_NONE, - SHADER_SPECIAL_TYPE_PROXY, - SHADER_SPECIAL_TYPE_AUTOCONVERT, - SHADER_SPECIAL_TYPE_GEOMETRY, - SHADER_SPECIAL_TYPE_SCRIPT, - SHADER_SPECIAL_TYPE_IMAGE_SLOT, - SHADER_SPECIAL_TYPE_CLOSURE, - SHADER_SPECIAL_TYPE_COMBINE_CLOSURE, - SHADER_SPECIAL_TYPE_OUTPUT, - SHADER_SPECIAL_TYPE_BUMP, + SHADER_SPECIAL_TYPE_NONE, + SHADER_SPECIAL_TYPE_PROXY, + SHADER_SPECIAL_TYPE_AUTOCONVERT, + SHADER_SPECIAL_TYPE_GEOMETRY, + SHADER_SPECIAL_TYPE_SCRIPT, + SHADER_SPECIAL_TYPE_IMAGE_SLOT, + SHADER_SPECIAL_TYPE_CLOSURE, + SHADER_SPECIAL_TYPE_COMBINE_CLOSURE, + SHADER_SPECIAL_TYPE_OUTPUT, + SHADER_SPECIAL_TYPE_BUMP, }; /* Input @@ -81,22 +76,38 @@ enum ShaderNodeSpecialType { * coordinate. */ class ShaderInput { -public: - ShaderInput(const SocketType& socket_type_, ShaderNode* parent_) - : socket_type(socket_type_), parent(parent_), link(NULL), stack_offset(SVM_STACK_INVALID) - {} - - ustring name() { return socket_type.ui_name; } - int flags() { return socket_type.flags; } - SocketType::Type type() { return socket_type.type; } - - void set(float f) { ((Node*)parent)->set(socket_type, f); } - void set(float3 f) { ((Node*)parent)->set(socket_type, f); } - - const SocketType& socket_type; - ShaderNode *parent; - ShaderOutput *link; - int stack_offset; /* for SVM compiler */ + public: + ShaderInput(const SocketType &socket_type_, ShaderNode *parent_) + : socket_type(socket_type_), parent(parent_), link(NULL), stack_offset(SVM_STACK_INVALID) + { + } + + ustring name() + { + return socket_type.ui_name; + } + int flags() + { + return socket_type.flags; + } + SocketType::Type type() + { + return socket_type.type; + } + + void set(float f) + { + ((Node *)parent)->set(socket_type, f); + } + void set(float3 f) + { + ((Node *)parent)->set(socket_type, f); + } + + const SocketType &socket_type; + ShaderNode *parent; + ShaderOutput *link; + int stack_offset; /* for SVM compiler */ }; /* Output @@ -104,18 +115,25 @@ public: * Output socket for a shader node. */ class ShaderOutput { -public: - ShaderOutput(const SocketType& socket_type_, ShaderNode* parent_) - : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID) - {} - - ustring name() { return socket_type.ui_name; } - SocketType::Type type() { return socket_type.type; } - - const SocketType& socket_type; - ShaderNode *parent; - vector<ShaderInput*> links; - int stack_offset; /* for SVM compiler */ + public: + ShaderOutput(const SocketType &socket_type_, ShaderNode *parent_) + : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID) + { + } + + ustring name() + { + return socket_type.ui_name; + } + SocketType::Type type() + { + return socket_type.type; + } + + const SocketType &socket_type; + ShaderNode *parent; + vector<ShaderInput *> links; + int stack_offset; /* for SVM compiler */ }; /* Node @@ -124,115 +142,163 @@ public: * base class for all node types. */ class ShaderNode : public Node { -public: - explicit ShaderNode(const NodeType *type); - virtual ~ShaderNode(); - - void create_inputs_outputs(const NodeType *type); - - ShaderInput *input(const char *name); - ShaderOutput *output(const char *name); - ShaderInput *input(ustring name); - ShaderOutput *output(ustring name); - - virtual ShaderNode *clone() const = 0; - virtual void attributes(Shader *shader, AttributeRequestSet *attributes); - virtual void compile(SVMCompiler& compiler) = 0; - virtual void compile(OSLCompiler& compiler) = 0; - - /* ** Node optimization ** */ - /* Check whether the node can be replaced with single constant. */ - virtual void constant_fold(const ConstantFolder& /*folder*/) {} - - /* Simplify settings used by artists to the ones which are simpler to - * evaluate in the kernel but keep the final result unchanged. - */ - virtual void simplify_settings(Scene * /*scene*/) {}; - - virtual bool has_surface_emission() { return false; } - virtual bool has_surface_transparent() { return false; } - virtual bool has_surface_bssrdf() { return false; } - virtual bool has_bump() { return false; } - virtual bool has_bssrdf_bump() { return false; } - virtual bool has_spatial_varying() { return false; } - virtual bool has_object_dependency() { return false; } - virtual bool has_attribute_dependency() { return false; } - virtual bool has_integrator_dependency() { return false; } - virtual bool has_volume_support() { return false; } - virtual bool has_raytrace() { return false; } - vector<ShaderInput*> inputs; - vector<ShaderOutput*> outputs; - - int id; /* index in graph node array */ - ShaderBump bump; /* for bump mapping utility */ - - ShaderNodeSpecialType special_type; /* special node type */ - - /* ** Selective nodes compilation ** */ - - /* TODO(sergey): More explicitly mention in the function names - * that those functions are for selective compilation only? - */ - - /* Nodes are split into several groups, group of level 0 contains - * nodes which are most commonly used, further levels are extension - * of previous one and includes less commonly used nodes. - */ - virtual int get_group() { return NODE_GROUP_LEVEL_0; } - - /* Node feature are used to disable huge nodes inside the group, - * so it's possible to disable huge nodes inside of the required - * nodes group. - */ - virtual int get_feature() { return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; } - - /* Get closure ID to which the node compiles into. */ - virtual ClosureType get_closure_type() { return CLOSURE_NONE_ID; } - - /* Check whether settings of the node equals to another one. - * - * This is mainly used to check whether two nodes can be merged - * together. Meaning, runtime stuff like node id and unbound slots - * will be ignored for comparison. - * - * NOTE: If some node can't be de-duplicated for whatever reason it - * is to be handled in the subclass. - */ - virtual bool equals(const ShaderNode& other); + public: + explicit ShaderNode(const NodeType *type); + virtual ~ShaderNode(); + + void create_inputs_outputs(const NodeType *type); + + ShaderInput *input(const char *name); + ShaderOutput *output(const char *name); + ShaderInput *input(ustring name); + ShaderOutput *output(ustring name); + + virtual ShaderNode *clone() const = 0; + virtual void attributes(Shader *shader, AttributeRequestSet *attributes); + virtual void compile(SVMCompiler &compiler) = 0; + virtual void compile(OSLCompiler &compiler) = 0; + + /* ** Node optimization ** */ + /* Check whether the node can be replaced with single constant. */ + virtual void constant_fold(const ConstantFolder & /*folder*/) + { + } + + /* Simplify settings used by artists to the ones which are simpler to + * evaluate in the kernel but keep the final result unchanged. + */ + virtual void simplify_settings(Scene * /*scene*/){}; + + virtual bool has_surface_emission() + { + return false; + } + virtual bool has_surface_transparent() + { + return false; + } + virtual bool has_surface_bssrdf() + { + return false; + } + virtual bool has_bump() + { + return false; + } + virtual bool has_bssrdf_bump() + { + return false; + } + virtual bool has_spatial_varying() + { + return false; + } + virtual bool has_object_dependency() + { + return false; + } + virtual bool has_attribute_dependency() + { + return false; + } + virtual bool has_integrator_dependency() + { + return false; + } + virtual bool has_volume_support() + { + return false; + } + virtual bool has_raytrace() + { + return false; + } + vector<ShaderInput *> inputs; + vector<ShaderOutput *> outputs; + + int id; /* index in graph node array */ + ShaderBump bump; /* for bump mapping utility */ + + ShaderNodeSpecialType special_type; /* special node type */ + + /* ** Selective nodes compilation ** */ + + /* TODO(sergey): More explicitly mention in the function names + * that those functions are for selective compilation only? + */ + + /* Nodes are split into several groups, group of level 0 contains + * nodes which are most commonly used, further levels are extension + * of previous one and includes less commonly used nodes. + */ + virtual int get_group() + { + return NODE_GROUP_LEVEL_0; + } + + /* Node feature are used to disable huge nodes inside the group, + * so it's possible to disable huge nodes inside of the required + * nodes group. + */ + virtual int get_feature() + { + return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; + } + + /* Get closure ID to which the node compiles into. */ + virtual ClosureType get_closure_type() + { + return CLOSURE_NONE_ID; + } + + /* Check whether settings of the node equals to another one. + * + * This is mainly used to check whether two nodes can be merged + * together. Meaning, runtime stuff like node id and unbound slots + * will be ignored for comparison. + * + * NOTE: If some node can't be de-duplicated for whatever reason it + * is to be handled in the subclass. + */ + virtual bool equals(const ShaderNode &other); }; - /* Node definition utility macros */ #define SHADER_NODE_CLASS(type) \ - NODE_DECLARE \ - type(); \ - virtual ShaderNode *clone() const { return new type(*this); } \ - virtual void compile(SVMCompiler& compiler); \ - virtual void compile(OSLCompiler& compiler); \ + NODE_DECLARE \ + type(); \ + virtual ShaderNode *clone() const \ + { \ + return new type(*this); \ + } \ + virtual void compile(SVMCompiler &compiler); \ + virtual void compile(OSLCompiler &compiler); #define SHADER_NODE_NO_CLONE_CLASS(type) \ - NODE_DECLARE \ - type(); \ - virtual void compile(SVMCompiler& compiler); \ - virtual void compile(OSLCompiler& compiler); \ + NODE_DECLARE \ + type(); \ + virtual void compile(SVMCompiler &compiler); \ + virtual void compile(OSLCompiler &compiler); #define SHADER_NODE_BASE_CLASS(type) \ - virtual ShaderNode *clone() const { return new type(*this); } \ - virtual void compile(SVMCompiler& compiler); \ - virtual void compile(OSLCompiler& compiler); \ - -class ShaderNodeIDComparator -{ -public: - bool operator()(const ShaderNode *n1, const ShaderNode *n2) const - { - return n1->id < n2->id; - } + virtual ShaderNode *clone() const \ + { \ + return new type(*this); \ + } \ + virtual void compile(SVMCompiler &compiler); \ + virtual void compile(OSLCompiler &compiler); + +class ShaderNodeIDComparator { + public: + bool operator()(const ShaderNode *n1, const ShaderNode *n2) const + { + return n1->id < n2->id; + } }; -typedef set<ShaderNode*, ShaderNodeIDComparator> ShaderNodeSet; -typedef map<ShaderNode*, ShaderNode*, ShaderNodeIDComparator> ShaderNodeMap; +typedef set<ShaderNode *, ShaderNodeIDComparator> ShaderNodeSet; +typedef map<ShaderNode *, ShaderNode *, ShaderNodeIDComparator> ShaderNodeMap; /* Graph * @@ -240,57 +306,57 @@ typedef map<ShaderNode*, ShaderNode*, ShaderNodeIDComparator> ShaderNodeMap; * bump mapping from displacement, and possibly other things in the future. */ class ShaderGraph { -public: - list<ShaderNode*> nodes; - size_t num_node_ids; - bool finalized; - bool simplified; - string displacement_hash; - - ShaderGraph(); - ~ShaderGraph(); - - ShaderNode *add(ShaderNode *node); - OutputNode *output(); - - void connect(ShaderOutput *from, ShaderInput *to); - void disconnect(ShaderOutput *from); - void disconnect(ShaderInput *to); - void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); - - void remove_proxy_nodes(); - void compute_displacement_hash(); - void simplify(Scene *scene); - void finalize(Scene *scene, - bool do_bump = false, - bool do_simplify = false, - bool bump_in_object_space = false); - - int get_num_closures(); - - void dump_graph(const char *filename); - -protected: - typedef pair<ShaderNode* const, ShaderNode*> NodePair; - - void find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input); - void clear_nodes(); - void copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap); - - void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack); - void bump_from_displacement(bool use_object_space); - void refine_bump_nodes(); - void default_inputs(bool do_osl); - void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume); - - /* Graph simplification routines. */ - void clean(Scene *scene); - void constant_fold(Scene *scene); - void simplify_settings(Scene *scene); - void deduplicate_nodes(); - void verify_volume_output(); + public: + list<ShaderNode *> nodes; + size_t num_node_ids; + bool finalized; + bool simplified; + string displacement_hash; + + ShaderGraph(); + ~ShaderGraph(); + + ShaderNode *add(ShaderNode *node); + OutputNode *output(); + + void connect(ShaderOutput *from, ShaderInput *to); + void disconnect(ShaderOutput *from); + void disconnect(ShaderInput *to); + void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); + + void remove_proxy_nodes(); + void compute_displacement_hash(); + void simplify(Scene *scene); + void finalize(Scene *scene, + bool do_bump = false, + bool do_simplify = false, + bool bump_in_object_space = false); + + int get_num_closures(); + + void dump_graph(const char *filename); + + protected: + typedef pair<ShaderNode *const, ShaderNode *> NodePair; + + void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input); + void clear_nodes(); + void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap); + + void break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack); + void bump_from_displacement(bool use_object_space); + void refine_bump_nodes(); + void default_inputs(bool do_osl); + void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume); + + /* Graph simplification routines. */ + void clean(Scene *scene); + void constant_fold(Scene *scene); + void simplify_settings(Scene *scene); + void deduplicate_nodes(); + void verify_volume_output(); }; CCL_NAMESPACE_END -#endif /* __GRAPH_H__ */ +#endif /* __GRAPH_H__ */ diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 1edd5865836..ae219e912e0 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -27,7 +27,7 @@ #include "util/util_unique_ptr.h" #ifdef WITH_OSL -#include <OSL/oslexec.h> +# include <OSL/oslexec.h> #endif CCL_NAMESPACE_BEGIN @@ -37,15 +37,15 @@ namespace { /* Some helpers to silence warning in templated function. */ bool isfinite(uchar /*value*/) { - return true; + return true; } bool isfinite(half /*value*/) { - return true; + return true; } -bool isfinite(uint16_t /*value*/) +bool isfinite(uint16_t /*value*/) { - return true; + return true; } /* The lower three bits of a device texture slot number indicate its type. @@ -54,946 +54,888 @@ bool isfinite(uint16_t /*value*/) */ int type_index_to_flattened_slot(int slot, ImageDataType type) { - return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); + return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); } int flattened_slot_to_type_index(int flat_slot, ImageDataType *type) { - *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); - return flat_slot >> IMAGE_DATA_TYPE_SHIFT; + *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); + return flat_slot >> IMAGE_DATA_TYPE_SHIFT; } -const char* name_from_type(ImageDataType type) +const char *name_from_type(ImageDataType type) { - switch(type) { - case IMAGE_DATA_TYPE_FLOAT4: return "float4"; - case IMAGE_DATA_TYPE_BYTE4: return "byte4"; - case IMAGE_DATA_TYPE_HALF4: return "half4"; - case IMAGE_DATA_TYPE_FLOAT: return "float"; - case IMAGE_DATA_TYPE_BYTE: return "byte"; - case IMAGE_DATA_TYPE_HALF: return "half"; - case IMAGE_DATA_TYPE_USHORT4: return "ushort4"; - case IMAGE_DATA_TYPE_USHORT: return "ushort"; - case IMAGE_DATA_NUM_TYPES: - assert(!"System enumerator type, should never be used"); - return ""; - } - assert(!"Unhandled image data type"); - return ""; + switch (type) { + case IMAGE_DATA_TYPE_FLOAT4: + return "float4"; + case IMAGE_DATA_TYPE_BYTE4: + return "byte4"; + case IMAGE_DATA_TYPE_HALF4: + return "half4"; + case IMAGE_DATA_TYPE_FLOAT: + return "float"; + case IMAGE_DATA_TYPE_BYTE: + return "byte"; + case IMAGE_DATA_TYPE_HALF: + return "half"; + case IMAGE_DATA_TYPE_USHORT4: + return "ushort4"; + case IMAGE_DATA_TYPE_USHORT: + return "ushort"; + case IMAGE_DATA_NUM_TYPES: + assert(!"System enumerator type, should never be used"); + return ""; + } + assert(!"Unhandled image data type"); + return ""; } } // namespace -ImageManager::ImageManager(const DeviceInfo& info) +ImageManager::ImageManager(const DeviceInfo &info) { - need_update = true; - osl_texture_system = NULL; - animation_frame = 0; + need_update = true; + osl_texture_system = NULL; + animation_frame = 0; - /* Set image limits */ - max_num_images = TEX_NUM_MAX; - has_half_images = info.has_half_images; + /* Set image limits */ + max_num_images = TEX_NUM_MAX; + has_half_images = info.has_half_images; - for(size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - tex_num_images[type] = 0; - } + for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + tex_num_images[type] = 0; + } } ImageManager::~ImageManager() { - for(size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) - assert(!images[type][slot]); - } + for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) + assert(!images[type][slot]); + } } void ImageManager::set_osl_texture_system(void *texture_system) { - osl_texture_system = texture_system; + osl_texture_system = texture_system; } bool ImageManager::set_animation_frame_update(int frame) { - if(frame != animation_frame) { - animation_frame = frame; - - for(size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(images[type][slot] && images[type][slot]->animated) - return true; - } - } - } - - return false; + if (frame != animation_frame) { + animation_frame = frame; + + for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) { + if (images[type][slot] && images[type][slot]->animated) + return true; + } + } + } + + return false; } device_memory *ImageManager::image_memory(int flat_slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + ImageDataType type; + int slot = flattened_slot_to_type_index(flat_slot, &type); - Image *img = images[type][slot]; + Image *img = images[type][slot]; - return img->mem; + return img->mem; } -bool ImageManager::get_image_metadata(int flat_slot, - ImageMetaData& metadata) +bool ImageManager::get_image_metadata(int flat_slot, ImageMetaData &metadata) { - if(flat_slot == -1) { - return false; - } + if (flat_slot == -1) { + return false; + } - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + ImageDataType type; + int slot = flattened_slot_to_type_index(flat_slot, &type); - Image *img = images[type][slot]; - if(img) { - metadata = img->metadata; - return true; - } + Image *img = images[type][slot]; + if (img) { + metadata = img->metadata; + return true; + } - return false; + return false; } -bool ImageManager::get_image_metadata(const string& filename, +bool ImageManager::get_image_metadata(const string &filename, void *builtin_data, - ImageMetaData& metadata) + ImageMetaData &metadata) { - memset(&metadata, 0, sizeof(metadata)); - - if(builtin_data) { - if(builtin_image_info_cb) { - builtin_image_info_cb(filename, builtin_data, metadata); - } - else { - return false; - } - - if(metadata.is_float) { - metadata.is_linear = true; - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 - : IMAGE_DATA_TYPE_FLOAT; - } - else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 - : IMAGE_DATA_TYPE_BYTE; - } - - return true; - } - - /* Perform preliminary checks, with meaningful logging. */ - if(!path_exists(filename)) { - VLOG(1) << "File '" << filename << "' does not exist."; - return false; - } - if(path_is_directory(filename)) { - VLOG(1) << "File '" << filename - << "' is a directory, can't use as image."; - return false; - } - - unique_ptr<ImageInput> in(ImageInput::create(filename)); - - if(!in) { - return false; - } - - ImageSpec spec; - if(!in->open(filename, spec)) { - return false; - } - - metadata.width = spec.width; - metadata.height = spec.height; - metadata.depth = spec.depth; - - - /* Check the main format, and channel formats. */ - size_t channel_size = spec.format.basesize(); - - if(spec.format.is_floating_point()) { - metadata.is_float = true; - metadata.is_linear = true; - } - - for(size_t channel = 0; channel < spec.channelformats.size(); channel++) { - channel_size = max(channel_size, spec.channelformats[channel].basesize()); - if(spec.channelformats[channel].is_floating_point()) { - metadata.is_float = true; - metadata.is_linear = true; - } - } - - /* check if it's half float */ - if(spec.format == TypeDesc::HALF) { - metadata.is_half = true; - } - - /* basic color space detection, not great but better than nothing - * before we do OpenColorIO integration */ - if(metadata.is_float) { - string colorspace = spec.get_string_attribute("oiio:ColorSpace"); - - metadata.is_linear = !(colorspace == "sRGB" || - colorspace == "GammaCorrected" || - (colorspace == "" && - (strcmp(in->format_name(), "png") == 0 || - strcmp(in->format_name(), "tiff") == 0 || - strcmp(in->format_name(), "dpx") == 0 || - strcmp(in->format_name(), "jpeg2000") == 0))); - } - else { - metadata.is_linear = false; - } - - /* set type and channels */ - metadata.channels = spec.nchannels; - - if(metadata.is_half) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 - : IMAGE_DATA_TYPE_HALF; - } - else if(metadata.is_float) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 - : IMAGE_DATA_TYPE_FLOAT; - } - else if(spec.format == TypeDesc::USHORT) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 - : IMAGE_DATA_TYPE_USHORT; - } - else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 - : IMAGE_DATA_TYPE_BYTE; - } - - in->close(); - - return true; + memset(&metadata, 0, sizeof(metadata)); + + if (builtin_data) { + if (builtin_image_info_cb) { + builtin_image_info_cb(filename, builtin_data, metadata); + } + else { + return false; + } + + if (metadata.is_float) { + metadata.is_linear = true; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; + } + else { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + } + + return true; + } + + /* Perform preliminary checks, with meaningful logging. */ + if (!path_exists(filename)) { + VLOG(1) << "File '" << filename << "' does not exist."; + return false; + } + if (path_is_directory(filename)) { + VLOG(1) << "File '" << filename << "' is a directory, can't use as image."; + return false; + } + + unique_ptr<ImageInput> in(ImageInput::create(filename)); + + if (!in) { + return false; + } + + ImageSpec spec; + if (!in->open(filename, spec)) { + return false; + } + + metadata.width = spec.width; + metadata.height = spec.height; + metadata.depth = spec.depth; + + /* Check the main format, and channel formats. */ + size_t channel_size = spec.format.basesize(); + + if (spec.format.is_floating_point()) { + metadata.is_float = true; + metadata.is_linear = true; + } + + for (size_t channel = 0; channel < spec.channelformats.size(); channel++) { + channel_size = max(channel_size, spec.channelformats[channel].basesize()); + if (spec.channelformats[channel].is_floating_point()) { + metadata.is_float = true; + metadata.is_linear = true; + } + } + + /* check if it's half float */ + if (spec.format == TypeDesc::HALF) { + metadata.is_half = true; + } + + /* basic color space detection, not great but better than nothing + * before we do OpenColorIO integration */ + if (metadata.is_float) { + string colorspace = spec.get_string_attribute("oiio:ColorSpace"); + + metadata.is_linear = !( + colorspace == "sRGB" || colorspace == "GammaCorrected" || + (colorspace == "" && + (strcmp(in->format_name(), "png") == 0 || strcmp(in->format_name(), "tiff") == 0 || + strcmp(in->format_name(), "dpx") == 0 || strcmp(in->format_name(), "jpeg2000") == 0))); + } + else { + metadata.is_linear = false; + } + + /* set type and channels */ + metadata.channels = spec.nchannels; + + if (metadata.is_half) { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; + } + else if (metadata.is_float) { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; + } + else if (spec.format == TypeDesc::USHORT) { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT; + } + else { + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + } + + in->close(); + + return true; } static bool image_equals(ImageManager::Image *image, - const string& filename, + const string &filename, void *builtin_data, InterpolationType interpolation, ExtensionType extension, bool use_alpha) { - return image->filename == filename && - image->builtin_data == builtin_data && - image->interpolation == interpolation && - image->extension == extension && - image->use_alpha == use_alpha; + return image->filename == filename && image->builtin_data == builtin_data && + image->interpolation == interpolation && image->extension == extension && + image->use_alpha == use_alpha; } -int ImageManager::add_image(const string& filename, +int ImageManager::add_image(const string &filename, void *builtin_data, bool animated, float frame, InterpolationType interpolation, ExtensionType extension, bool use_alpha, - ImageMetaData& metadata) + ImageMetaData &metadata) { - Image *img; - size_t slot; - - get_image_metadata(filename, builtin_data, metadata); - ImageDataType type = metadata.type; - - thread_scoped_lock device_lock(device_mutex); - - /* No half textures on OpenCL, use full float instead. */ - if(!has_half_images) { - if(type == IMAGE_DATA_TYPE_HALF4) { - type = IMAGE_DATA_TYPE_FLOAT4; - } - else if(type == IMAGE_DATA_TYPE_HALF) { - type = IMAGE_DATA_TYPE_FLOAT; - } - } - - /* Fnd existing image. */ - for(slot = 0; slot < images[type].size(); slot++) { - img = images[type][slot]; - if(img && image_equals(img, - filename, - builtin_data, - interpolation, - extension, - use_alpha)) - { - if(img->frame != frame) { - img->frame = frame; - img->need_load = true; - } - if(img->use_alpha != use_alpha) { - img->use_alpha = use_alpha; - img->need_load = true; - } - if(!(img->metadata == metadata)) { - img->metadata = metadata; - img->need_load = true; - } - img->users++; - return type_index_to_flattened_slot(slot, type); - } - } - - /* Find free slot. */ - for(slot = 0; slot < images[type].size(); slot++) { - if(!images[type][slot]) - break; - } - - /* Count if we're over the limit. - * Very unlikely, since max_num_images is insanely big. But better safe - * than sorry. - */ - int tex_count = 0; - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - tex_count += tex_num_images[type]; - } - if(tex_count > max_num_images) { - printf("ImageManager::add_image: Reached image limit (%d), " - "skipping '%s'\n", max_num_images, filename.c_str()); - return -1; - } - - if(slot == images[type].size()) { - images[type].resize(images[type].size() + 1); - } - - /* Add new image. */ - img = new Image(); - img->filename = filename; - img->builtin_data = builtin_data; - img->metadata = metadata; - img->need_load = true; - img->animated = animated; - img->frame = frame; - img->interpolation = interpolation; - img->extension = extension; - img->users = 1; - img->use_alpha = use_alpha; - img->mem = NULL; - - images[type][slot] = img; - - ++tex_num_images[type]; - - need_update = true; - - return type_index_to_flattened_slot(slot, type); + Image *img; + size_t slot; + + get_image_metadata(filename, builtin_data, metadata); + ImageDataType type = metadata.type; + + thread_scoped_lock device_lock(device_mutex); + + /* No half textures on OpenCL, use full float instead. */ + if (!has_half_images) { + if (type == IMAGE_DATA_TYPE_HALF4) { + type = IMAGE_DATA_TYPE_FLOAT4; + } + else if (type == IMAGE_DATA_TYPE_HALF) { + type = IMAGE_DATA_TYPE_FLOAT; + } + } + + /* Fnd existing image. */ + for (slot = 0; slot < images[type].size(); slot++) { + img = images[type][slot]; + if (img && image_equals(img, filename, builtin_data, interpolation, extension, use_alpha)) { + if (img->frame != frame) { + img->frame = frame; + img->need_load = true; + } + if (img->use_alpha != use_alpha) { + img->use_alpha = use_alpha; + img->need_load = true; + } + if (!(img->metadata == metadata)) { + img->metadata = metadata; + img->need_load = true; + } + img->users++; + return type_index_to_flattened_slot(slot, type); + } + } + + /* Find free slot. */ + for (slot = 0; slot < images[type].size(); slot++) { + if (!images[type][slot]) + break; + } + + /* Count if we're over the limit. + * Very unlikely, since max_num_images is insanely big. But better safe + * than sorry. + */ + int tex_count = 0; + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + tex_count += tex_num_images[type]; + } + if (tex_count > max_num_images) { + printf( + "ImageManager::add_image: Reached image limit (%d), " + "skipping '%s'\n", + max_num_images, + filename.c_str()); + return -1; + } + + if (slot == images[type].size()) { + images[type].resize(images[type].size() + 1); + } + + /* Add new image. */ + img = new Image(); + img->filename = filename; + img->builtin_data = builtin_data; + img->metadata = metadata; + img->need_load = true; + img->animated = animated; + img->frame = frame; + img->interpolation = interpolation; + img->extension = extension; + img->users = 1; + img->use_alpha = use_alpha; + img->mem = NULL; + + images[type][slot] = img; + + ++tex_num_images[type]; + + need_update = true; + + return type_index_to_flattened_slot(slot, type); } void ImageManager::remove_image(int flat_slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + ImageDataType type; + int slot = flattened_slot_to_type_index(flat_slot, &type); - Image *image = images[type][slot]; - assert(image && image->users >= 1); + Image *image = images[type][slot]; + assert(image && image->users >= 1); - /* decrement user count */ - image->users--; + /* decrement user count */ + image->users--; - /* don't remove immediately, rather do it all together later on. one of - * the reasons for this is that on shader changes we add and remove nodes - * that use them, but we do not want to reload the image all the time. */ - if(image->users == 0) - need_update = true; + /* don't remove immediately, rather do it all together later on. one of + * the reasons for this is that on shader changes we add and remove nodes + * that use them, but we do not want to reload the image all the time. */ + if (image->users == 0) + need_update = true; } -void ImageManager::remove_image(const string& filename, +void ImageManager::remove_image(const string &filename, void *builtin_data, InterpolationType interpolation, ExtensionType extension, bool use_alpha) { - size_t slot; - - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(slot = 0; slot < images[type].size(); slot++) { - if(images[type][slot] && image_equals(images[type][slot], - filename, - builtin_data, - interpolation, - extension, - use_alpha)) - { - remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type)); - return; - } - } - } + size_t slot; + + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (slot = 0; slot < images[type].size(); slot++) { + if (images[type][slot] && + image_equals( + images[type][slot], filename, builtin_data, interpolation, extension, use_alpha)) { + remove_image(type_index_to_flattened_slot(slot, (ImageDataType)type)); + return; + } + } + } } /* TODO(sergey): Deduplicate with the iteration above, but make it pretty, * without bunch of arguments passing around making code readability even * more cluttered. */ -void ImageManager::tag_reload_image(const string& filename, +void ImageManager::tag_reload_image(const string &filename, void *builtin_data, InterpolationType interpolation, ExtensionType extension, bool use_alpha) { - for(size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(images[type][slot] && image_equals(images[type][slot], - filename, - builtin_data, - interpolation, - extension, - use_alpha)) - { - images[type][slot]->need_load = true; - break; - } - } - } + for (size_t type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) { + if (images[type][slot] && + image_equals( + images[type][slot], filename, builtin_data, interpolation, extension, use_alpha)) { + images[type][slot]->need_load = true; + break; + } + } + } } -bool ImageManager::file_load_image_generic(Image *img, - unique_ptr<ImageInput> *in) +bool ImageManager::file_load_image_generic(Image *img, unique_ptr<ImageInput> *in) { - if(img->filename == "") - return false; - - if(!img->builtin_data) { - /* NOTE: Error logging is done in meta data acquisition. */ - if(!path_exists(img->filename) || path_is_directory(img->filename)) { - return false; - } - - /* load image from file through OIIO */ - *in = unique_ptr<ImageInput>(ImageInput::create(img->filename)); - - if(!*in) - return false; - - ImageSpec spec = ImageSpec(); - ImageSpec config = ImageSpec(); - - if(img->use_alpha == false) - config.attribute("oiio:UnassociatedAlpha", 1); - - if(!(*in)->open(img->filename, spec, config)) { - return false; - } - } - else { - /* load image using builtin images callbacks */ - if(!builtin_image_info_cb || !builtin_image_pixels_cb) - return false; - } - - /* we only handle certain number of components */ - if(!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) { - if(*in) { - (*in)->close(); - } - return false; - } - - return true; + if (img->filename == "") + return false; + + if (!img->builtin_data) { + /* NOTE: Error logging is done in meta data acquisition. */ + if (!path_exists(img->filename) || path_is_directory(img->filename)) { + return false; + } + + /* load image from file through OIIO */ + *in = unique_ptr<ImageInput>(ImageInput::create(img->filename)); + + if (!*in) + return false; + + ImageSpec spec = ImageSpec(); + ImageSpec config = ImageSpec(); + + if (img->use_alpha == false) + config.attribute("oiio:UnassociatedAlpha", 1); + + if (!(*in)->open(img->filename, spec, config)) { + return false; + } + } + else { + /* load image using builtin images callbacks */ + if (!builtin_image_info_cb || !builtin_image_pixels_cb) + return false; + } + + /* we only handle certain number of components */ + if (!(img->metadata.channels >= 1 && img->metadata.channels <= 4)) { + if (*in) { + (*in)->close(); + } + return false; + } + + return true; } -template<TypeDesc::BASETYPE FileFormat, - typename StorageType, - typename DeviceType> +template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType> bool ImageManager::file_load_image(Image *img, ImageDataType type, int texture_limit, - device_vector<DeviceType>& tex_img) + device_vector<DeviceType> &tex_img) { - unique_ptr<ImageInput> in = NULL; - if(!file_load_image_generic(img, &in)) { - return false; - } - - /* Get metadata. */ - int width = img->metadata.width; - int height = img->metadata.height; - int depth = img->metadata.depth; - int components = img->metadata.channels; - - /* Read RGBA pixels. */ - vector<StorageType> pixels_storage; - StorageType *pixels; - const size_t max_size = max(max(width, height), depth); - if(max_size == 0) { - /* Don't bother with invalid images. */ - return false; - } - if(texture_limit > 0 && max_size > texture_limit) { - pixels_storage.resize(((size_t)width)*height*depth*4); - pixels = &pixels_storage[0]; - } - else { - thread_scoped_lock device_lock(device_mutex); - pixels = (StorageType*)tex_img.alloc(width, height, depth); - } - if(pixels == NULL) { - /* Could be that we've run out of memory. */ - return false; - } - bool cmyk = false; - const size_t num_pixels = ((size_t)width) * height * depth; - if(in) { - StorageType *readpixels = pixels; - vector<StorageType> tmppixels; - if(components > 4) { - tmppixels.resize(((size_t)width)*height*components); - readpixels = &tmppixels[0]; - } - if(depth <= 1) { - size_t scanlinesize = ((size_t)width)*components*sizeof(StorageType); - in->read_image(FileFormat, - (uchar*)readpixels + (height-1)*scanlinesize, - AutoStride, - -scanlinesize, - AutoStride); - } - else { - in->read_image(FileFormat, (uchar*)readpixels); - } - if(components > 4) { - size_t dimensions = ((size_t)width)*height; - for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { - pixels[i*4+3] = tmppixels[i*components+3]; - pixels[i*4+2] = tmppixels[i*components+2]; - pixels[i*4+1] = tmppixels[i*components+1]; - pixels[i*4+0] = tmppixels[i*components+0]; - } - tmppixels.clear(); - } - cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; - in->close(); - } - else { - if(FileFormat == TypeDesc::FLOAT) { - builtin_image_float_pixels_cb(img->filename, - img->builtin_data, - (float*)&pixels[0], - num_pixels * components, - img->metadata.builtin_free_cache); - } - else if(FileFormat == TypeDesc::UINT8) { - builtin_image_pixels_cb(img->filename, - img->builtin_data, - (uchar*)&pixels[0], - num_pixels * components, - img->metadata.builtin_free_cache); - } - else { - /* TODO(dingto): Support half for ImBuf. */ - } - } - /* Check if we actually have a float4 slot, in case components == 1, - * but device doesn't support single channel textures. - */ - bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || - type == IMAGE_DATA_TYPE_HALF4 || - type == IMAGE_DATA_TYPE_BYTE4 || - type == IMAGE_DATA_TYPE_USHORT4); - if(is_rgba) { - const StorageType one = util_image_cast_from_float<StorageType>(1.0f); - - if(cmyk) { - /* CMYK */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - float c = util_image_cast_to_float(pixels[i*4+0]); - float m = util_image_cast_to_float(pixels[i*4+1]); - float y = util_image_cast_to_float(pixels[i*4+2]); - float k = util_image_cast_to_float(pixels[i*4+3]); - pixels[i*4+0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k)); - pixels[i*4+1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k)); - pixels[i*4+2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k)); - pixels[i*4+3] = one; - } - } - else if(components == 2) { - /* grayscale + alpha */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = pixels[i*2+1]; - pixels[i*4+2] = pixels[i*2+0]; - pixels[i*4+1] = pixels[i*2+0]; - pixels[i*4+0] = pixels[i*2+0]; - } - } - else if(components == 3) { - /* RGB */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = one; - pixels[i*4+2] = pixels[i*3+2]; - pixels[i*4+1] = pixels[i*3+1]; - pixels[i*4+0] = pixels[i*3+0]; - } - } - else if(components == 1) { - /* grayscale */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = one; - pixels[i*4+2] = pixels[i]; - pixels[i*4+1] = pixels[i]; - pixels[i*4+0] = pixels[i]; - } - } - if(img->use_alpha == false) { - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = one; - } - } - } - /* Make sure we don't have buggy values. */ - if(FileFormat == TypeDesc::FLOAT) { - /* For RGBA buffers we put all channels to 0 if either of them is not - * finite. This way we avoid possible artifacts caused by fully changed - * hue. - */ - if(is_rgba) { - for(size_t i = 0; i < num_pixels; i += 4) { - StorageType *pixel = &pixels[i*4]; - if(!isfinite(pixel[0]) || - !isfinite(pixel[1]) || - !isfinite(pixel[2]) || - !isfinite(pixel[3])) - { - pixel[0] = 0; - pixel[1] = 0; - pixel[2] = 0; - pixel[3] = 0; - } - } - } - else { - for(size_t i = 0; i < num_pixels; ++i) { - StorageType *pixel = &pixels[i]; - if(!isfinite(pixel[0])) { - pixel[0] = 0; - } - } - } - } - /* Scale image down if needed. */ - if(pixels_storage.size() > 0) { - float scale_factor = 1.0f; - while(max_size * scale_factor > texture_limit) { - scale_factor *= 0.5f; - } - VLOG(1) << "Scaling image " << img->filename - << " by a factor of " << scale_factor << "."; - vector<StorageType> scaled_pixels; - size_t scaled_width, scaled_height, scaled_depth; - util_image_resize_pixels(pixels_storage, - width, height, depth, - is_rgba ? 4 : 1, - scale_factor, - &scaled_pixels, - &scaled_width, &scaled_height, &scaled_depth); - - StorageType *texture_pixels; - - { - thread_scoped_lock device_lock(device_mutex); - texture_pixels = (StorageType*)tex_img.alloc(scaled_width, - scaled_height, - scaled_depth); - } - - memcpy(texture_pixels, - &scaled_pixels[0], - scaled_pixels.size() * sizeof(StorageType)); - } - return true; + unique_ptr<ImageInput> in = NULL; + if (!file_load_image_generic(img, &in)) { + return false; + } + + /* Get metadata. */ + int width = img->metadata.width; + int height = img->metadata.height; + int depth = img->metadata.depth; + int components = img->metadata.channels; + + /* Read RGBA pixels. */ + vector<StorageType> pixels_storage; + StorageType *pixels; + const size_t max_size = max(max(width, height), depth); + if (max_size == 0) { + /* Don't bother with invalid images. */ + return false; + } + if (texture_limit > 0 && max_size > texture_limit) { + pixels_storage.resize(((size_t)width) * height * depth * 4); + pixels = &pixels_storage[0]; + } + else { + thread_scoped_lock device_lock(device_mutex); + pixels = (StorageType *)tex_img.alloc(width, height, depth); + } + if (pixels == NULL) { + /* Could be that we've run out of memory. */ + return false; + } + bool cmyk = false; + const size_t num_pixels = ((size_t)width) * height * depth; + if (in) { + StorageType *readpixels = pixels; + vector<StorageType> tmppixels; + if (components > 4) { + tmppixels.resize(((size_t)width) * height * components); + readpixels = &tmppixels[0]; + } + if (depth <= 1) { + size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType); + in->read_image(FileFormat, + (uchar *)readpixels + (height - 1) * scanlinesize, + AutoStride, + -scanlinesize, + AutoStride); + } + else { + in->read_image(FileFormat, (uchar *)readpixels); + } + if (components > 4) { + size_t dimensions = ((size_t)width) * height; + for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) { + pixels[i * 4 + 3] = tmppixels[i * components + 3]; + pixels[i * 4 + 2] = tmppixels[i * components + 2]; + pixels[i * 4 + 1] = tmppixels[i * components + 1]; + pixels[i * 4 + 0] = tmppixels[i * components + 0]; + } + tmppixels.clear(); + } + cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; + in->close(); + } + else { + if (FileFormat == TypeDesc::FLOAT) { + builtin_image_float_pixels_cb(img->filename, + img->builtin_data, + (float *)&pixels[0], + num_pixels * components, + img->metadata.builtin_free_cache); + } + else if (FileFormat == TypeDesc::UINT8) { + builtin_image_pixels_cb(img->filename, + img->builtin_data, + (uchar *)&pixels[0], + num_pixels * components, + img->metadata.builtin_free_cache); + } + else { + /* TODO(dingto): Support half for ImBuf. */ + } + } + /* Check if we actually have a float4 slot, in case components == 1, + * but device doesn't support single channel textures. + */ + bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4); + if (is_rgba) { + const StorageType one = util_image_cast_from_float<StorageType>(1.0f); + + if (cmyk) { + /* CMYK */ + for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { + float c = util_image_cast_to_float(pixels[i * 4 + 0]); + float m = util_image_cast_to_float(pixels[i * 4 + 1]); + float y = util_image_cast_to_float(pixels[i * 4 + 2]); + float k = util_image_cast_to_float(pixels[i * 4 + 3]); + pixels[i * 4 + 0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k)); + pixels[i * 4 + 1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k)); + pixels[i * 4 + 2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k)); + pixels[i * 4 + 3] = one; + } + } + else if (components == 2) { + /* grayscale + alpha */ + for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i * 4 + 3] = pixels[i * 2 + 1]; + pixels[i * 4 + 2] = pixels[i * 2 + 0]; + pixels[i * 4 + 1] = pixels[i * 2 + 0]; + pixels[i * 4 + 0] = pixels[i * 2 + 0]; + } + } + else if (components == 3) { + /* RGB */ + for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i * 4 + 3] = one; + pixels[i * 4 + 2] = pixels[i * 3 + 2]; + pixels[i * 4 + 1] = pixels[i * 3 + 1]; + pixels[i * 4 + 0] = pixels[i * 3 + 0]; + } + } + else if (components == 1) { + /* grayscale */ + for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i * 4 + 3] = one; + pixels[i * 4 + 2] = pixels[i]; + pixels[i * 4 + 1] = pixels[i]; + pixels[i * 4 + 0] = pixels[i]; + } + } + if (img->use_alpha == false) { + for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i * 4 + 3] = one; + } + } + } + /* Make sure we don't have buggy values. */ + if (FileFormat == TypeDesc::FLOAT) { + /* For RGBA buffers we put all channels to 0 if either of them is not + * finite. This way we avoid possible artifacts caused by fully changed + * hue. + */ + if (is_rgba) { + for (size_t i = 0; i < num_pixels; i += 4) { + StorageType *pixel = &pixels[i * 4]; + if (!isfinite(pixel[0]) || !isfinite(pixel[1]) || !isfinite(pixel[2]) || + !isfinite(pixel[3])) { + pixel[0] = 0; + pixel[1] = 0; + pixel[2] = 0; + pixel[3] = 0; + } + } + } + else { + for (size_t i = 0; i < num_pixels; ++i) { + StorageType *pixel = &pixels[i]; + if (!isfinite(pixel[0])) { + pixel[0] = 0; + } + } + } + } + /* Scale image down if needed. */ + if (pixels_storage.size() > 0) { + float scale_factor = 1.0f; + while (max_size * scale_factor > texture_limit) { + scale_factor *= 0.5f; + } + VLOG(1) << "Scaling image " << img->filename << " by a factor of " << scale_factor << "."; + vector<StorageType> scaled_pixels; + size_t scaled_width, scaled_height, scaled_depth; + util_image_resize_pixels(pixels_storage, + width, + height, + depth, + is_rgba ? 4 : 1, + scale_factor, + &scaled_pixels, + &scaled_width, + &scaled_height, + &scaled_depth); + + StorageType *texture_pixels; + + { + thread_scoped_lock device_lock(device_mutex); + texture_pixels = (StorageType *)tex_img.alloc(scaled_width, scaled_height, scaled_depth); + } + + memcpy(texture_pixels, &scaled_pixels[0], scaled_pixels.size() * sizeof(StorageType)); + } + return true; } -void ImageManager::device_load_image(Device *device, - Scene *scene, - ImageDataType type, - int slot, - Progress *progress) +void ImageManager::device_load_image( + Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress) { - if(progress->get_cancel()) - return; - - Image *img = images[type][slot]; - - if(osl_texture_system && !img->builtin_data) - return; - - string filename = path_filename(images[type][slot]->filename); - progress->set_status("Updating Images", "Loading " + filename); - - const int texture_limit = scene->params.texture_limit; - - /* Slot assignment */ - int flat_slot = type_index_to_flattened_slot(slot, type); - img->mem_name = string_printf("__tex_image_%s_%03d", - name_from_type(type), flat_slot); - - /* Free previous texture in slot. */ - if(img->mem) { - thread_scoped_lock device_lock(device_mutex); - delete img->mem; - img->mem = NULL; - } - - /* Create new texture. */ - if(type == IMAGE_DATA_TYPE_FLOAT4) { - device_vector<float4> *tex_img - = new device_vector<float4>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::FLOAT, float>(img, - type, - texture_limit, - *tex_img)) - { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - float *pixels = (float*)tex_img->alloc(1, 1); - - pixels[0] = TEX_IMAGE_MISSING_R; - pixels[1] = TEX_IMAGE_MISSING_G; - pixels[2] = TEX_IMAGE_MISSING_B; - pixels[3] = TEX_IMAGE_MISSING_A; - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_FLOAT) { - device_vector<float> *tex_img - = new device_vector<float>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::FLOAT, float>(img, - type, - texture_limit, - *tex_img)) - { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - float *pixels = (float*)tex_img->alloc(1, 1); - - pixels[0] = TEX_IMAGE_MISSING_R; - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_BYTE4) { - device_vector<uchar4> *tex_img - = new device_vector<uchar4>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::UINT8, uchar>(img, - type, - texture_limit, - *tex_img)) - { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - uchar *pixels = (uchar*)tex_img->alloc(1, 1); - - pixels[0] = (TEX_IMAGE_MISSING_R * 255); - pixels[1] = (TEX_IMAGE_MISSING_G * 255); - pixels[2] = (TEX_IMAGE_MISSING_B * 255); - pixels[3] = (TEX_IMAGE_MISSING_A * 255); - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_BYTE) { - device_vector<uchar> *tex_img - = new device_vector<uchar>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::UINT8, uchar>(img, - type, - texture_limit, - *tex_img)) { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - uchar *pixels = (uchar*)tex_img->alloc(1, 1); - - pixels[0] = (TEX_IMAGE_MISSING_R * 255); - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_HALF4) { - device_vector<half4> *tex_img - = new device_vector<half4>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::HALF, half>(img, - type, - texture_limit, - *tex_img)) { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - half *pixels = (half*)tex_img->alloc(1, 1); - - pixels[0] = TEX_IMAGE_MISSING_R; - pixels[1] = TEX_IMAGE_MISSING_G; - pixels[2] = TEX_IMAGE_MISSING_B; - pixels[3] = TEX_IMAGE_MISSING_A; - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_USHORT) { - device_vector<uint16_t> *tex_img - = new device_vector<uint16_t>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::USHORT, uint16_t>(img, - type, - texture_limit, - *tex_img)) { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - uint16_t *pixels = (uint16_t*)tex_img->alloc(1, 1); - - pixels[0] = (TEX_IMAGE_MISSING_R * 65535); - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_USHORT4) { - device_vector<ushort4> *tex_img - = new device_vector<ushort4>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::USHORT, uint16_t>(img, - type, - texture_limit, - *tex_img)) { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - uint16_t *pixels = (uint16_t*)tex_img->alloc(1, 1); - - pixels[0] = (TEX_IMAGE_MISSING_R * 65535); - pixels[1] = (TEX_IMAGE_MISSING_G * 65535); - pixels[2] = (TEX_IMAGE_MISSING_B * 65535); - pixels[3] = (TEX_IMAGE_MISSING_A * 65535); - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - else if(type == IMAGE_DATA_TYPE_HALF) { - device_vector<half> *tex_img - = new device_vector<half>(device, img->mem_name.c_str(), MEM_TEXTURE); - - if(!file_load_image<TypeDesc::HALF, half>(img, - type, - texture_limit, - *tex_img)) { - /* on failure to load, we set a 1x1 pixels pink image */ - thread_scoped_lock device_lock(device_mutex); - half *pixels = (half*)tex_img->alloc(1, 1); - - pixels[0] = TEX_IMAGE_MISSING_R; - } - - img->mem = tex_img; - img->mem->interpolation = img->interpolation; - img->mem->extension = img->extension; - - thread_scoped_lock device_lock(device_mutex); - tex_img->copy_to_device(); - } - img->need_load = false; + if (progress->get_cancel()) + return; + + Image *img = images[type][slot]; + + if (osl_texture_system && !img->builtin_data) + return; + + string filename = path_filename(images[type][slot]->filename); + progress->set_status("Updating Images", "Loading " + filename); + + const int texture_limit = scene->params.texture_limit; + + /* Slot assignment */ + int flat_slot = type_index_to_flattened_slot(slot, type); + img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), flat_slot); + + /* Free previous texture in slot. */ + if (img->mem) { + thread_scoped_lock device_lock(device_mutex); + delete img->mem; + img->mem = NULL; + } + + /* Create new texture. */ + if (type == IMAGE_DATA_TYPE_FLOAT4) { + device_vector<float4> *tex_img = new device_vector<float4>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + float *pixels = (float *)tex_img->alloc(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + pixels[1] = TEX_IMAGE_MISSING_G; + pixels[2] = TEX_IMAGE_MISSING_B; + pixels[3] = TEX_IMAGE_MISSING_A; + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_FLOAT) { + device_vector<float> *tex_img = new device_vector<float>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::FLOAT, float>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + float *pixels = (float *)tex_img->alloc(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_BYTE4) { + device_vector<uchar4> *tex_img = new device_vector<uchar4>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + uchar *pixels = (uchar *)tex_img->alloc(1, 1); + + pixels[0] = (TEX_IMAGE_MISSING_R * 255); + pixels[1] = (TEX_IMAGE_MISSING_G * 255); + pixels[2] = (TEX_IMAGE_MISSING_B * 255); + pixels[3] = (TEX_IMAGE_MISSING_A * 255); + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_BYTE) { + device_vector<uchar> *tex_img = new device_vector<uchar>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::UINT8, uchar>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + uchar *pixels = (uchar *)tex_img->alloc(1, 1); + + pixels[0] = (TEX_IMAGE_MISSING_R * 255); + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_HALF4) { + device_vector<half4> *tex_img = new device_vector<half4>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + half *pixels = (half *)tex_img->alloc(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + pixels[1] = TEX_IMAGE_MISSING_G; + pixels[2] = TEX_IMAGE_MISSING_B; + pixels[3] = TEX_IMAGE_MISSING_A; + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_USHORT) { + device_vector<uint16_t> *tex_img = new device_vector<uint16_t>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1); + + pixels[0] = (TEX_IMAGE_MISSING_R * 65535); + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_USHORT4) { + device_vector<ushort4> *tex_img = new device_vector<ushort4>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::USHORT, uint16_t>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + uint16_t *pixels = (uint16_t *)tex_img->alloc(1, 1); + + pixels[0] = (TEX_IMAGE_MISSING_R * 65535); + pixels[1] = (TEX_IMAGE_MISSING_G * 65535); + pixels[2] = (TEX_IMAGE_MISSING_B * 65535); + pixels[3] = (TEX_IMAGE_MISSING_A * 65535); + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + else if (type == IMAGE_DATA_TYPE_HALF) { + device_vector<half> *tex_img = new device_vector<half>( + device, img->mem_name.c_str(), MEM_TEXTURE); + + if (!file_load_image<TypeDesc::HALF, half>(img, type, texture_limit, *tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + thread_scoped_lock device_lock(device_mutex); + half *pixels = (half *)tex_img->alloc(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + } + + img->mem = tex_img; + img->mem->interpolation = img->interpolation; + img->mem->extension = img->extension; + + thread_scoped_lock device_lock(device_mutex); + tex_img->copy_to_device(); + } + img->need_load = false; } void ImageManager::device_free_image(Device *, ImageDataType type, int slot) { - Image *img = images[type][slot]; + Image *img = images[type][slot]; - if(img) { - if(osl_texture_system && !img->builtin_data) { + if (img) { + if (osl_texture_system && !img->builtin_data) { #ifdef WITH_OSL - ustring filename(images[type][slot]->filename); - ((OSL::TextureSystem*)osl_texture_system)->invalidate(filename); + ustring filename(images[type][slot]->filename); + ((OSL::TextureSystem *)osl_texture_system)->invalidate(filename); #endif - } + } - if(img->mem) { - thread_scoped_lock device_lock(device_mutex); - delete img->mem; - } + if (img->mem) { + thread_scoped_lock device_lock(device_mutex); + delete img->mem; + } - delete img; - images[type][slot] = NULL; - --tex_num_images[type]; - } + delete img; + images[type][slot] = NULL; + --tex_num_images[type]; + } } -void ImageManager::device_update(Device *device, - Scene *scene, - Progress& progress) +void ImageManager::device_update(Device *device, Scene *scene, Progress &progress) { - if(!need_update) { - return; - } - - TaskPool pool; - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(!images[type][slot]) - continue; - - if(images[type][slot]->users == 0) { - device_free_image(device, (ImageDataType)type, slot); - } - else if(images[type][slot]->need_load) { - if(!osl_texture_system || images[type][slot]->builtin_data) - pool.push(function_bind(&ImageManager::device_load_image, - this, - device, - scene, - (ImageDataType)type, - slot, - &progress)); - } - } - } - - pool.wait_work(); - - need_update = false; + if (!need_update) { + return; + } + + TaskPool pool; + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) { + if (!images[type][slot]) + continue; + + if (images[type][slot]->users == 0) { + device_free_image(device, (ImageDataType)type, slot); + } + else if (images[type][slot]->need_load) { + if (!osl_texture_system || images[type][slot]->builtin_data) + pool.push(function_bind(&ImageManager::device_load_image, + this, + device, + scene, + (ImageDataType)type, + slot, + &progress)); + } + } + } + + pool.wait_work(); + + need_update = false; } void ImageManager::device_update_slot(Device *device, @@ -1001,87 +943,80 @@ void ImageManager::device_update_slot(Device *device, int flat_slot, Progress *progress) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); - - Image *image = images[type][slot]; - assert(image != NULL); - - if(image->users == 0) { - device_free_image(device, type, slot); - } - else if(image->need_load) { - if(!osl_texture_system || image->builtin_data) - device_load_image(device, - scene, - type, - slot, - progress); - } + ImageDataType type; + int slot = flattened_slot_to_type_index(flat_slot, &type); + + Image *image = images[type][slot]; + assert(image != NULL); + + if (image->users == 0) { + device_free_image(device, type, slot); + } + else if (image->need_load) { + if (!osl_texture_system || image->builtin_data) + device_load_image(device, scene, type, slot, progress); + } } -void ImageManager::device_load_builtin(Device *device, - Scene *scene, - Progress& progress) +void ImageManager::device_load_builtin(Device *device, Scene *scene, Progress &progress) { - /* Load only builtin images, Blender needs this to load evaluated - * scene data from depsgraph before it is freed. */ - if(!need_update) { - return; - } - - TaskPool pool; - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(!images[type][slot]) - continue; - - if(images[type][slot]->need_load) { - if(images[type][slot]->builtin_data) { - pool.push(function_bind(&ImageManager::device_load_image, - this, - device, - scene, - (ImageDataType)type, - slot, - &progress)); - } - } - } - } - - pool.wait_work(); + /* Load only builtin images, Blender needs this to load evaluated + * scene data from depsgraph before it is freed. */ + if (!need_update) { + return; + } + + TaskPool pool; + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) { + if (!images[type][slot]) + continue; + + if (images[type][slot]->need_load) { + if (images[type][slot]->builtin_data) { + pool.push(function_bind(&ImageManager::device_load_image, + this, + device, + scene, + (ImageDataType)type, + slot, + &progress)); + } + } + } + } + + pool.wait_work(); } void ImageManager::device_free_builtin(Device *device) { - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) { - if(images[type][slot] && images[type][slot]->builtin_data) - device_free_image(device, (ImageDataType)type, slot); - } - } + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) { + if (images[type][slot] && images[type][slot]->builtin_data) + device_free_image(device, (ImageDataType)type, slot); + } + } } void ImageManager::device_free(Device *device) { - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - for(size_t slot = 0; slot < images[type].size(); slot++) { - device_free_image(device, (ImageDataType)type, slot); - } - images[type].clear(); - } + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + for (size_t slot = 0; slot < images[type].size(); slot++) { + device_free_image(device, (ImageDataType)type, slot); + } + images[type].clear(); + } } void ImageManager::collect_statistics(RenderStats *stats) { - for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { - foreach(const Image *image, images[type]) { - stats->image.textures.add_entry( - NamedSizeEntry(path_filename(image->filename), - image->mem->memory_size())); - } - } + for (int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + foreach (const Image *image, images[type]) { + stats->image.textures.add_entry( + NamedSizeEntry(path_filename(image->filename), image->mem->memory_size())); + } + } } CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 1403b9050fd..34f046692f6 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -34,150 +34,129 @@ class RenderStats; class Scene; class ImageMetaData { -public: - /* Must be set by image file or builtin callback. */ - bool is_float, is_half; - int channels; - size_t width, height, depth; - bool builtin_free_cache; - - /* Automatically set. */ - ImageDataType type; - bool is_linear; - - bool operator==(const ImageMetaData& other) const - { - return is_float == other.is_float && - is_half == other.is_half && - channels == other.channels && - width == other.width && - height == other.height && - depth == other.depth && - type == other.type && - is_linear == other.is_linear; - } + public: + /* Must be set by image file or builtin callback. */ + bool is_float, is_half; + int channels; + size_t width, height, depth; + bool builtin_free_cache; + + /* Automatically set. */ + ImageDataType type; + bool is_linear; + + bool operator==(const ImageMetaData &other) const + { + return is_float == other.is_float && is_half == other.is_half && channels == other.channels && + width == other.width && height == other.height && depth == other.depth && + type == other.type && is_linear == other.is_linear; + } }; class ImageManager { -public: - explicit ImageManager(const DeviceInfo& info); - ~ImageManager(); - - int add_image(const string& filename, - void *builtin_data, - bool animated, - float frame, - InterpolationType interpolation, - ExtensionType extension, - bool use_alpha, - ImageMetaData& metadata); - void remove_image(int flat_slot); - void remove_image(const string& filename, - void *builtin_data, - InterpolationType interpolation, - ExtensionType extension, - bool use_alpha); - void tag_reload_image(const string& filename, - void *builtin_data, - InterpolationType interpolation, - ExtensionType extension, - bool use_alpha); - bool get_image_metadata(const string& filename, - void *builtin_data, - ImageMetaData& metadata); - bool get_image_metadata(int flat_slot, - ImageMetaData& metadata); - - void device_update(Device *device, - Scene *scene, - Progress& progress); - void device_update_slot(Device *device, - Scene *scene, - int flat_slot, - Progress *progress); - void device_free(Device *device); - - void device_load_builtin(Device *device, - Scene *scene, - Progress& progress); - void device_free_builtin(Device *device); - - void set_osl_texture_system(void *texture_system); - bool set_animation_frame_update(int frame); - - device_memory *image_memory(int flat_slot); - - void collect_statistics(RenderStats *stats); - - bool need_update; - - /* NOTE: Here pixels_size is a size of storage, which equals to - * width * height * depth. - * Use this to avoid some nasty memory corruptions. - */ - function<void(const string &filename, - void *data, - ImageMetaData& metadata)> builtin_image_info_cb; - function<bool(const string &filename, - void *data, - unsigned char *pixels, - const size_t pixels_size, - const bool free_cache)> builtin_image_pixels_cb; - function<bool(const string &filename, - void *data, - float *pixels, - const size_t pixels_size, - const bool free_cache)> builtin_image_float_pixels_cb; - - struct Image { - string filename; - void *builtin_data; - ImageMetaData metadata; - - bool use_alpha; - bool need_load; - bool animated; - float frame; - InterpolationType interpolation; - ExtensionType extension; - - string mem_name; - device_memory *mem; - - int users; - }; - -private: - int tex_num_images[IMAGE_DATA_NUM_TYPES]; - int max_num_images; - bool has_half_images; - - thread_mutex device_mutex; - int animation_frame; - - vector<Image*> images[IMAGE_DATA_NUM_TYPES]; - void *osl_texture_system; - - bool file_load_image_generic(Image *img, unique_ptr<ImageInput> *in); - - template<TypeDesc::BASETYPE FileFormat, - typename StorageType, - typename DeviceType> - bool file_load_image(Image *img, - ImageDataType type, - int texture_limit, - device_vector<DeviceType>& tex_img); - - void device_load_image(Device *device, - Scene *scene, - ImageDataType type, - int slot, - Progress *progress); - void device_free_image(Device *device, - ImageDataType type, - int slot); + public: + explicit ImageManager(const DeviceInfo &info); + ~ImageManager(); + + int add_image(const string &filename, + void *builtin_data, + bool animated, + float frame, + InterpolationType interpolation, + ExtensionType extension, + bool use_alpha, + ImageMetaData &metadata); + void remove_image(int flat_slot); + void remove_image(const string &filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension, + bool use_alpha); + void tag_reload_image(const string &filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension, + bool use_alpha); + bool get_image_metadata(const string &filename, void *builtin_data, ImageMetaData &metadata); + bool get_image_metadata(int flat_slot, ImageMetaData &metadata); + + void device_update(Device *device, Scene *scene, Progress &progress); + void device_update_slot(Device *device, Scene *scene, int flat_slot, Progress *progress); + void device_free(Device *device); + + void device_load_builtin(Device *device, Scene *scene, Progress &progress); + void device_free_builtin(Device *device); + + void set_osl_texture_system(void *texture_system); + bool set_animation_frame_update(int frame); + + device_memory *image_memory(int flat_slot); + + void collect_statistics(RenderStats *stats); + + bool need_update; + + /* NOTE: Here pixels_size is a size of storage, which equals to + * width * height * depth. + * Use this to avoid some nasty memory corruptions. + */ + function<void(const string &filename, void *data, ImageMetaData &metadata)> + builtin_image_info_cb; + function<bool(const string &filename, + void *data, + unsigned char *pixels, + const size_t pixels_size, + const bool free_cache)> + builtin_image_pixels_cb; + function<bool(const string &filename, + void *data, + float *pixels, + const size_t pixels_size, + const bool free_cache)> + builtin_image_float_pixels_cb; + + struct Image { + string filename; + void *builtin_data; + ImageMetaData metadata; + + bool use_alpha; + bool need_load; + bool animated; + float frame; + InterpolationType interpolation; + ExtensionType extension; + + string mem_name; + device_memory *mem; + + int users; + }; + + private: + int tex_num_images[IMAGE_DATA_NUM_TYPES]; + int max_num_images; + bool has_half_images; + + thread_mutex device_mutex; + int animation_frame; + + vector<Image *> images[IMAGE_DATA_NUM_TYPES]; + void *osl_texture_system; + + bool file_load_image_generic(Image *img, unique_ptr<ImageInput> *in); + + template<TypeDesc::BASETYPE FileFormat, typename StorageType, typename DeviceType> + bool file_load_image(Image *img, + ImageDataType type, + int texture_limit, + device_vector<DeviceType> &tex_img); + + void device_load_image( + Device *device, Scene *scene, ImageDataType type, int slot, Progress *progress); + void device_free_image(Device *device, ImageDataType type, int slot); }; CCL_NAMESPACE_END -#endif /* __IMAGE_H__ */ +#endif /* __IMAGE_H__ */ diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index d86eb8fc5d3..d3873dcfe46 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -30,61 +30,60 @@ CCL_NAMESPACE_BEGIN NODE_DEFINE(Integrator) { - NodeType *type = NodeType::add("integrator", create); - - SOCKET_INT(max_bounce, "Max Bounce", 7); - - SOCKET_INT(max_diffuse_bounce, "Max Diffuse Bounce", 7); - SOCKET_INT(max_glossy_bounce, "Max Glossy Bounce", 7); - SOCKET_INT(max_transmission_bounce, "Max Transmission Bounce", 7); - SOCKET_INT(max_volume_bounce, "Max Volume Bounce", 7); - - SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7); - - SOCKET_INT(ao_bounces, "AO Bounces", 0); - - SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024); - SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f); - - SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true); - SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true); - SOCKET_FLOAT(filter_glossy, "Filter Glossy", 0.0f); - SOCKET_INT(seed, "Seed", 0); - SOCKET_FLOAT(sample_clamp_direct, "Sample Clamp Direct", 0.0f); - SOCKET_FLOAT(sample_clamp_indirect, "Sample Clamp Indirect", 0.0f); - SOCKET_BOOLEAN(motion_blur, "Motion Blur", false); - - SOCKET_INT(aa_samples, "AA Samples", 0); - SOCKET_INT(diffuse_samples, "Diffuse Samples", 1); - SOCKET_INT(glossy_samples, "Glossy Samples", 1); - SOCKET_INT(transmission_samples, "Transmission Samples", 1); - SOCKET_INT(ao_samples, "AO Samples", 1); - SOCKET_INT(mesh_light_samples, "Mesh Light Samples", 1); - SOCKET_INT(subsurface_samples, "Subsurface Samples", 1); - SOCKET_INT(volume_samples, "Volume Samples", 1); - SOCKET_INT(start_sample, "Start Sample", 0); - - SOCKET_BOOLEAN(sample_all_lights_direct, "Sample All Lights Direct", true); - SOCKET_BOOLEAN(sample_all_lights_indirect, "Sample All Lights Indirect", true); - SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f); - - static NodeEnum method_enum; - method_enum.insert("path", PATH); - method_enum.insert("branched_path", BRANCHED_PATH); - SOCKET_ENUM(method, "Method", method_enum, PATH); - - static NodeEnum sampling_pattern_enum; - sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL); - sampling_pattern_enum.insert("cmj", SAMPLING_PATTERN_CMJ); - SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_SOBOL); - - return type; + NodeType *type = NodeType::add("integrator", create); + + SOCKET_INT(max_bounce, "Max Bounce", 7); + + SOCKET_INT(max_diffuse_bounce, "Max Diffuse Bounce", 7); + SOCKET_INT(max_glossy_bounce, "Max Glossy Bounce", 7); + SOCKET_INT(max_transmission_bounce, "Max Transmission Bounce", 7); + SOCKET_INT(max_volume_bounce, "Max Volume Bounce", 7); + + SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7); + + SOCKET_INT(ao_bounces, "AO Bounces", 0); + + SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024); + SOCKET_FLOAT(volume_step_size, "Volume Step Size", 0.1f); + + SOCKET_BOOLEAN(caustics_reflective, "Reflective Caustics", true); + SOCKET_BOOLEAN(caustics_refractive, "Refractive Caustics", true); + SOCKET_FLOAT(filter_glossy, "Filter Glossy", 0.0f); + SOCKET_INT(seed, "Seed", 0); + SOCKET_FLOAT(sample_clamp_direct, "Sample Clamp Direct", 0.0f); + SOCKET_FLOAT(sample_clamp_indirect, "Sample Clamp Indirect", 0.0f); + SOCKET_BOOLEAN(motion_blur, "Motion Blur", false); + + SOCKET_INT(aa_samples, "AA Samples", 0); + SOCKET_INT(diffuse_samples, "Diffuse Samples", 1); + SOCKET_INT(glossy_samples, "Glossy Samples", 1); + SOCKET_INT(transmission_samples, "Transmission Samples", 1); + SOCKET_INT(ao_samples, "AO Samples", 1); + SOCKET_INT(mesh_light_samples, "Mesh Light Samples", 1); + SOCKET_INT(subsurface_samples, "Subsurface Samples", 1); + SOCKET_INT(volume_samples, "Volume Samples", 1); + SOCKET_INT(start_sample, "Start Sample", 0); + + SOCKET_BOOLEAN(sample_all_lights_direct, "Sample All Lights Direct", true); + SOCKET_BOOLEAN(sample_all_lights_indirect, "Sample All Lights Indirect", true); + SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f); + + static NodeEnum method_enum; + method_enum.insert("path", PATH); + method_enum.insert("branched_path", BRANCHED_PATH); + SOCKET_ENUM(method, "Method", method_enum, PATH); + + static NodeEnum sampling_pattern_enum; + sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL); + sampling_pattern_enum.insert("cmj", SAMPLING_PATTERN_CMJ); + SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_SOBOL); + + return type; } -Integrator::Integrator() -: Node(node_type) +Integrator::Integrator() : Node(node_type) { - need_update = true; + need_update = true; } Integrator::~Integrator() @@ -93,146 +92,148 @@ Integrator::~Integrator() void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene) { - if(!need_update) - return; - - device_free(device, dscene); - - KernelIntegrator *kintegrator = &dscene->data.integrator; - - /* integrator parameters */ - kintegrator->max_bounce = max_bounce + 1; - - kintegrator->max_diffuse_bounce = max_diffuse_bounce + 1; - kintegrator->max_glossy_bounce = max_glossy_bounce + 1; - kintegrator->max_transmission_bounce = max_transmission_bounce + 1; - kintegrator->max_volume_bounce = max_volume_bounce + 1; - - kintegrator->transparent_max_bounce = transparent_max_bounce + 1; - - if(ao_bounces == 0) { - kintegrator->ao_bounces = INT_MAX; - } - else { - kintegrator->ao_bounces = ao_bounces - 1; - } - - /* Transparent Shadows - * We only need to enable transparent shadows, if we actually have - * transparent shaders in the scene. Otherwise we can disable it - * to improve performance a bit. */ - kintegrator->transparent_shadows = false; - foreach(Shader *shader, scene->shaders) { - /* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */ - if((shader->has_surface_transparent && shader->use_transparent_shadow) || shader->has_volume) { - kintegrator->transparent_shadows = true; - break; - } - } - - kintegrator->volume_max_steps = volume_max_steps; - kintegrator->volume_step_size = volume_step_size; - - kintegrator->caustics_reflective = caustics_reflective; - kintegrator->caustics_refractive = caustics_refractive; - kintegrator->filter_glossy = (filter_glossy == 0.0f)? FLT_MAX: 1.0f/filter_glossy; - - kintegrator->seed = hash_int(seed); - - kintegrator->use_ambient_occlusion = - ((Pass::contains(scene->film->passes, PASS_AO)) || dscene->data.background.ao_factor != 0.0f); - - kintegrator->sample_clamp_direct = (sample_clamp_direct == 0.0f)? FLT_MAX: sample_clamp_direct*3.0f; - kintegrator->sample_clamp_indirect = (sample_clamp_indirect == 0.0f)? FLT_MAX: sample_clamp_indirect*3.0f; - - kintegrator->branched = (method == BRANCHED_PATH); - kintegrator->volume_decoupled = device->info.has_volume_decoupled; - kintegrator->diffuse_samples = diffuse_samples; - kintegrator->glossy_samples = glossy_samples; - kintegrator->transmission_samples = transmission_samples; - kintegrator->ao_samples = ao_samples; - kintegrator->mesh_light_samples = mesh_light_samples; - kintegrator->subsurface_samples = subsurface_samples; - kintegrator->volume_samples = volume_samples; - kintegrator->start_sample = start_sample; - - if(method == BRANCHED_PATH) { - kintegrator->sample_all_lights_direct = sample_all_lights_direct; - kintegrator->sample_all_lights_indirect = sample_all_lights_indirect; - } - else { - kintegrator->sample_all_lights_direct = false; - kintegrator->sample_all_lights_indirect = false; - } - - kintegrator->sampling_pattern = sampling_pattern; - kintegrator->aa_samples = aa_samples; - - if(light_sampling_threshold > 0.0f) { - kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold; - } - else { - kintegrator->light_inv_rr_threshold = 0.0f; - } - - /* sobol directions table */ - int max_samples = 1; - - if(method == BRANCHED_PATH) { - foreach(Light *light, scene->lights) - max_samples = max(max_samples, light->samples); - - max_samples = max(max_samples, max(diffuse_samples, max(glossy_samples, transmission_samples))); - max_samples = max(max_samples, max(ao_samples, max(mesh_light_samples, subsurface_samples))); - max_samples = max(max_samples, volume_samples); - } - - uint total_bounces = max_bounce + - transparent_max_bounce + 3 + - VOLUME_BOUNDS_MAX + - max(BSSRDF_MAX_HITS, BSSRDF_MAX_BOUNCES); - - max_samples *= total_bounces; - - int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM; - dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS); - - uint *directions = dscene->sobol_directions.alloc(SOBOL_BITS*dimensions); - - sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions); - - dscene->sobol_directions.copy_to_device(); - - /* Clamping. */ - bool use_sample_clamp = (sample_clamp_direct != 0.0f || - sample_clamp_indirect != 0.0f); - if(use_sample_clamp != scene->film->use_sample_clamp) { - scene->film->use_sample_clamp = use_sample_clamp; - scene->film->tag_update(scene); - } - - need_update = false; + if (!need_update) + return; + + device_free(device, dscene); + + KernelIntegrator *kintegrator = &dscene->data.integrator; + + /* integrator parameters */ + kintegrator->max_bounce = max_bounce + 1; + + kintegrator->max_diffuse_bounce = max_diffuse_bounce + 1; + kintegrator->max_glossy_bounce = max_glossy_bounce + 1; + kintegrator->max_transmission_bounce = max_transmission_bounce + 1; + kintegrator->max_volume_bounce = max_volume_bounce + 1; + + kintegrator->transparent_max_bounce = transparent_max_bounce + 1; + + if (ao_bounces == 0) { + kintegrator->ao_bounces = INT_MAX; + } + else { + kintegrator->ao_bounces = ao_bounces - 1; + } + + /* Transparent Shadows + * We only need to enable transparent shadows, if we actually have + * transparent shaders in the scene. Otherwise we can disable it + * to improve performance a bit. */ + kintegrator->transparent_shadows = false; + foreach (Shader *shader, scene->shaders) { + /* keep this in sync with SD_HAS_TRANSPARENT_SHADOW in shader.cpp */ + if ((shader->has_surface_transparent && shader->use_transparent_shadow) || + shader->has_volume) { + kintegrator->transparent_shadows = true; + break; + } + } + + kintegrator->volume_max_steps = volume_max_steps; + kintegrator->volume_step_size = volume_step_size; + + kintegrator->caustics_reflective = caustics_reflective; + kintegrator->caustics_refractive = caustics_refractive; + kintegrator->filter_glossy = (filter_glossy == 0.0f) ? FLT_MAX : 1.0f / filter_glossy; + + kintegrator->seed = hash_int(seed); + + kintegrator->use_ambient_occlusion = ((Pass::contains(scene->film->passes, PASS_AO)) || + dscene->data.background.ao_factor != 0.0f); + + kintegrator->sample_clamp_direct = (sample_clamp_direct == 0.0f) ? FLT_MAX : + sample_clamp_direct * 3.0f; + kintegrator->sample_clamp_indirect = (sample_clamp_indirect == 0.0f) ? + FLT_MAX : + sample_clamp_indirect * 3.0f; + + kintegrator->branched = (method == BRANCHED_PATH); + kintegrator->volume_decoupled = device->info.has_volume_decoupled; + kintegrator->diffuse_samples = diffuse_samples; + kintegrator->glossy_samples = glossy_samples; + kintegrator->transmission_samples = transmission_samples; + kintegrator->ao_samples = ao_samples; + kintegrator->mesh_light_samples = mesh_light_samples; + kintegrator->subsurface_samples = subsurface_samples; + kintegrator->volume_samples = volume_samples; + kintegrator->start_sample = start_sample; + + if (method == BRANCHED_PATH) { + kintegrator->sample_all_lights_direct = sample_all_lights_direct; + kintegrator->sample_all_lights_indirect = sample_all_lights_indirect; + } + else { + kintegrator->sample_all_lights_direct = false; + kintegrator->sample_all_lights_indirect = false; + } + + kintegrator->sampling_pattern = sampling_pattern; + kintegrator->aa_samples = aa_samples; + + if (light_sampling_threshold > 0.0f) { + kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold; + } + else { + kintegrator->light_inv_rr_threshold = 0.0f; + } + + /* sobol directions table */ + int max_samples = 1; + + if (method == BRANCHED_PATH) { + foreach (Light *light, scene->lights) + max_samples = max(max_samples, light->samples); + + max_samples = max(max_samples, + max(diffuse_samples, max(glossy_samples, transmission_samples))); + max_samples = max(max_samples, max(ao_samples, max(mesh_light_samples, subsurface_samples))); + max_samples = max(max_samples, volume_samples); + } + + uint total_bounces = max_bounce + transparent_max_bounce + 3 + VOLUME_BOUNDS_MAX + + max(BSSRDF_MAX_HITS, BSSRDF_MAX_BOUNCES); + + max_samples *= total_bounces; + + int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM; + dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS); + + uint *directions = dscene->sobol_directions.alloc(SOBOL_BITS * dimensions); + + sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions); + + dscene->sobol_directions.copy_to_device(); + + /* Clamping. */ + bool use_sample_clamp = (sample_clamp_direct != 0.0f || sample_clamp_indirect != 0.0f); + if (use_sample_clamp != scene->film->use_sample_clamp) { + scene->film->use_sample_clamp = use_sample_clamp; + scene->film->tag_update(scene); + } + + need_update = false; } void Integrator::device_free(Device *, DeviceScene *dscene) { - dscene->sobol_directions.free(); + dscene->sobol_directions.free(); } -bool Integrator::modified(const Integrator& integrator) +bool Integrator::modified(const Integrator &integrator) { - return !Node::equals(integrator); + return !Node::equals(integrator); } void Integrator::tag_update(Scene *scene) { - foreach(Shader *shader, scene->shaders) { - if(shader->has_integrator_dependency) { - scene->shader_manager->need_update = true; - break; - } - } - need_update = true; + foreach (Shader *shader, scene->shaders) { + if (shader->has_integrator_dependency) { + scene->shader_manager->need_update = true; + break; + } + } + need_update = true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index da4e61d8153..6acc68a7402 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -28,74 +28,74 @@ class DeviceScene; class Scene; class Integrator : public Node { -public: - NODE_DECLARE + public: + NODE_DECLARE - int max_bounce; + int max_bounce; - int max_diffuse_bounce; - int max_glossy_bounce; - int max_transmission_bounce; - int max_volume_bounce; + int max_diffuse_bounce; + int max_glossy_bounce; + int max_transmission_bounce; + int max_volume_bounce; - int transparent_max_bounce; + int transparent_max_bounce; - int ao_bounces; + int ao_bounces; - int volume_max_steps; - float volume_step_size; + int volume_max_steps; + float volume_step_size; - bool caustics_reflective; - bool caustics_refractive; - float filter_glossy; + bool caustics_reflective; + bool caustics_refractive; + float filter_glossy; - int seed; + int seed; - float sample_clamp_direct; - float sample_clamp_indirect; - bool motion_blur; + float sample_clamp_direct; + float sample_clamp_indirect; + bool motion_blur; - /* Maximum number of samples, beyond which we are likely to run into - * precision issues for sampling patterns. */ - static const int MAX_SAMPLES = (1 << 24); + /* Maximum number of samples, beyond which we are likely to run into + * precision issues for sampling patterns. */ + static const int MAX_SAMPLES = (1 << 24); - int aa_samples; - int diffuse_samples; - int glossy_samples; - int transmission_samples; - int ao_samples; - int mesh_light_samples; - int subsurface_samples; - int volume_samples; - int start_sample; + int aa_samples; + int diffuse_samples; + int glossy_samples; + int transmission_samples; + int ao_samples; + int mesh_light_samples; + int subsurface_samples; + int volume_samples; + int start_sample; - bool sample_all_lights_direct; - bool sample_all_lights_indirect; - float light_sampling_threshold; + bool sample_all_lights_direct; + bool sample_all_lights_indirect; + float light_sampling_threshold; - enum Method { - BRANCHED_PATH = 0, - PATH = 1, + enum Method { + BRANCHED_PATH = 0, + PATH = 1, - NUM_METHODS, - }; + NUM_METHODS, + }; - Method method; + Method method; - SamplingPattern sampling_pattern; + SamplingPattern sampling_pattern; - bool need_update; + bool need_update; - Integrator(); - ~Integrator(); + Integrator(); + ~Integrator(); - void device_update(Device *device, DeviceScene *dscene, Scene *scene); - void device_free(Device *device, DeviceScene *dscene); + void device_update(Device *device, DeviceScene *dscene, Scene *scene); + void device_free(Device *device, DeviceScene *dscene); - bool modified(const Integrator& integrator); - void tag_update(Scene *scene); + bool modified(const Integrator &integrator); + void tag_update(Scene *scene); }; CCL_NAMESPACE_END -#endif /* __INTEGRATOR_H__ */ +#endif /* __INTEGRATOR_H__ */ diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 56d60adf71d..d4c233e3bb3 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -34,1002 +34,1016 @@ CCL_NAMESPACE_BEGIN -static void shade_background_pixels(Device *device, DeviceScene *dscene, int width, int height, vector<float3>& pixels, Progress& progress) +static void shade_background_pixels(Device *device, + DeviceScene *dscene, + int width, + int height, + vector<float3> &pixels, + Progress &progress) { - /* create input */ - device_vector<uint4> d_input(device, "background_input", MEM_READ_ONLY); - device_vector<float4> d_output(device, "background_output", MEM_READ_WRITE); - - uint4 *d_input_data = d_input.alloc(width*height); - - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { - float u = (x + 0.5f)/width; - float v = (y + 0.5f)/height; - - uint4 in = make_uint4(__float_as_int(u), __float_as_int(v), 0, 0); - d_input_data[x + y*width] = in; - } - } - - /* compute on device */ - d_output.alloc(width*height); - d_output.zero_to_device(); - d_input.copy_to_device(); - - device->const_copy_to("__data", &dscene->data, sizeof(dscene->data)); - - DeviceTask main_task(DeviceTask::SHADER); - main_task.shader_input = d_input.device_pointer; - main_task.shader_output = d_output.device_pointer; - main_task.shader_eval_type = SHADER_EVAL_BACKGROUND; - main_task.shader_x = 0; - main_task.shader_w = width*height; - main_task.num_samples = 1; - main_task.get_cancel = function_bind(&Progress::get_cancel, &progress); - - /* disabled splitting for now, there's an issue with multi-GPU mem_copy_from */ - list<DeviceTask> split_tasks; - main_task.split(split_tasks, 1, 128*128); - - foreach(DeviceTask& task, split_tasks) { - device->task_add(task); - device->task_wait(); - d_output.copy_from_device(task.shader_x, 1, task.shader_w); - } - - d_input.free(); - - float4 *d_output_data = d_output.data(); - - pixels.resize(width*height); - - for(int y = 0; y < height; y++) { - for(int x = 0; x < width; x++) { - pixels[y*width + x].x = d_output_data[y*width + x].x; - pixels[y*width + x].y = d_output_data[y*width + x].y; - pixels[y*width + x].z = d_output_data[y*width + x].z; - } - } - - d_output.free(); + /* create input */ + device_vector<uint4> d_input(device, "background_input", MEM_READ_ONLY); + device_vector<float4> d_output(device, "background_output", MEM_READ_WRITE); + + uint4 *d_input_data = d_input.alloc(width * height); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + float u = (x + 0.5f) / width; + float v = (y + 0.5f) / height; + + uint4 in = make_uint4(__float_as_int(u), __float_as_int(v), 0, 0); + d_input_data[x + y * width] = in; + } + } + + /* compute on device */ + d_output.alloc(width * height); + d_output.zero_to_device(); + d_input.copy_to_device(); + + device->const_copy_to("__data", &dscene->data, sizeof(dscene->data)); + + DeviceTask main_task(DeviceTask::SHADER); + main_task.shader_input = d_input.device_pointer; + main_task.shader_output = d_output.device_pointer; + main_task.shader_eval_type = SHADER_EVAL_BACKGROUND; + main_task.shader_x = 0; + main_task.shader_w = width * height; + main_task.num_samples = 1; + main_task.get_cancel = function_bind(&Progress::get_cancel, &progress); + + /* disabled splitting for now, there's an issue with multi-GPU mem_copy_from */ + list<DeviceTask> split_tasks; + main_task.split(split_tasks, 1, 128 * 128); + + foreach (DeviceTask &task, split_tasks) { + device->task_add(task); + device->task_wait(); + d_output.copy_from_device(task.shader_x, 1, task.shader_w); + } + + d_input.free(); + + float4 *d_output_data = d_output.data(); + + pixels.resize(width * height); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + pixels[y * width + x].x = d_output_data[y * width + x].x; + pixels[y * width + x].y = d_output_data[y * width + x].y; + pixels[y * width + x].z = d_output_data[y * width + x].z; + } + } + + d_output.free(); } /* Light */ NODE_DEFINE(Light) { - NodeType* type = NodeType::add("light", create); + NodeType *type = NodeType::add("light", create); - static NodeEnum type_enum; - type_enum.insert("point", LIGHT_POINT); - type_enum.insert("distant", LIGHT_DISTANT); - type_enum.insert("background", LIGHT_BACKGROUND); - type_enum.insert("area", LIGHT_AREA); - type_enum.insert("spot", LIGHT_SPOT); - SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT); + static NodeEnum type_enum; + type_enum.insert("point", LIGHT_POINT); + type_enum.insert("distant", LIGHT_DISTANT); + type_enum.insert("background", LIGHT_BACKGROUND); + type_enum.insert("area", LIGHT_AREA); + type_enum.insert("spot", LIGHT_SPOT); + SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT); - SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_FLOAT(size, "Size", 0.0f); + SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_FLOAT(size, "Size", 0.0f); - SOCKET_VECTOR(axisu, "Axis U", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_FLOAT(sizeu, "Size U", 1.0f); - SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_FLOAT(sizev, "Size V", 1.0f); - SOCKET_BOOLEAN(round, "Round", false); + SOCKET_VECTOR(axisu, "Axis U", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_FLOAT(sizeu, "Size U", 1.0f); + SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_FLOAT(sizev, "Size V", 1.0f); + SOCKET_BOOLEAN(round, "Round", false); - SOCKET_INT(map_resolution, "Map Resolution", 0); + SOCKET_INT(map_resolution, "Map Resolution", 0); - SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F); - SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f); + SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F); + SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f); - SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); - SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true); - SOCKET_BOOLEAN(use_mis, "Use Mis", false); - SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true); - SOCKET_BOOLEAN(use_glossy, "Use Glossy", true); - SOCKET_BOOLEAN(use_transmission, "Use Transmission", true); - SOCKET_BOOLEAN(use_scatter, "Use Scatter", true); + SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true); + SOCKET_BOOLEAN(use_mis, "Use Mis", false); + SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true); + SOCKET_BOOLEAN(use_glossy, "Use Glossy", true); + SOCKET_BOOLEAN(use_transmission, "Use Transmission", true); + SOCKET_BOOLEAN(use_scatter, "Use Scatter", true); - SOCKET_INT(samples, "Samples", 1); - SOCKET_INT(max_bounces, "Max Bounces", 1024); - SOCKET_UINT(random_id, "Random ID", 0); + SOCKET_INT(samples, "Samples", 1); + SOCKET_INT(max_bounces, "Max Bounces", 1024); + SOCKET_UINT(random_id, "Random ID", 0); - SOCKET_BOOLEAN(is_portal, "Is Portal", false); - SOCKET_BOOLEAN(is_enabled, "Is Enabled", true); + SOCKET_BOOLEAN(is_portal, "Is Portal", false); + SOCKET_BOOLEAN(is_enabled, "Is Enabled", true); - SOCKET_NODE(shader, "Shader", &Shader::node_type); + SOCKET_NODE(shader, "Shader", &Shader::node_type); - return type; + return type; } -Light::Light() -: Node(node_type) +Light::Light() : Node(node_type) { } void Light::tag_update(Scene *scene) { - scene->light_manager->need_update = true; + scene->light_manager->need_update = true; } bool Light::has_contribution(Scene *scene) { - if(is_portal) { - return false; - } - if(type == LIGHT_BACKGROUND) { - return true; - } - return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission; + if (is_portal) { + return false; + } + if (type == LIGHT_BACKGROUND) { + return true; + } + return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission; } /* Light Manager */ LightManager::LightManager() { - need_update = true; - use_light_visibility = false; + need_update = true; + use_light_visibility = false; } LightManager::~LightManager() { - foreach(IESSlot *slot, ies_slots) { - delete slot; - } + foreach (IESSlot *slot, ies_slots) { + delete slot; + } } bool LightManager::has_background_light(Scene *scene) { - foreach(Light *light, scene->lights) { - if(light->type == LIGHT_BACKGROUND && light->is_enabled) { - return true; - } - } - return false; + foreach (Light *light, scene->lights) { + if (light->type == LIGHT_BACKGROUND && light->is_enabled) { + return true; + } + } + return false; } void LightManager::disable_ineffective_light(Scene *scene) { - /* Make all lights enabled by default, and perform some preliminary checks - * needed for finer-tuning of settings (for example, check whether we've - * got portals or not). - */ - bool has_portal = false, has_background = false; - foreach(Light *light, scene->lights) { - light->is_enabled = light->has_contribution(scene); - has_portal |= light->is_portal; - has_background |= light->type == LIGHT_BACKGROUND; - } - - if(has_background) { - /* Ignore background light if: - * - If unsupported on a device - * - If we don't need it (no HDRs etc.) - */ - Shader *shader = (scene->background->shader) ? scene->background->shader : scene->default_background; - bool disable_mis = !(has_portal || shader->has_surface_spatial_varying); - if(disable_mis) { - VLOG(1) << "Background MIS has been disabled.\n"; - foreach(Light *light, scene->lights) { - if(light->type == LIGHT_BACKGROUND) { - light->is_enabled = false; - } - } - } - } + /* Make all lights enabled by default, and perform some preliminary checks + * needed for finer-tuning of settings (for example, check whether we've + * got portals or not). + */ + bool has_portal = false, has_background = false; + foreach (Light *light, scene->lights) { + light->is_enabled = light->has_contribution(scene); + has_portal |= light->is_portal; + has_background |= light->type == LIGHT_BACKGROUND; + } + + if (has_background) { + /* Ignore background light if: + * - If unsupported on a device + * - If we don't need it (no HDRs etc.) + */ + Shader *shader = (scene->background->shader) ? scene->background->shader : + scene->default_background; + bool disable_mis = !(has_portal || shader->has_surface_spatial_varying); + if (disable_mis) { + VLOG(1) << "Background MIS has been disabled.\n"; + foreach (Light *light, scene->lights) { + if (light->type == LIGHT_BACKGROUND) { + light->is_enabled = false; + } + } + } + } } -bool LightManager::object_usable_as_light(Object *object) { - Mesh *mesh = object->mesh; - /* Skip objects with NaNs */ - if(!object->bounds.valid()) { - return false; - } - /* Skip if we are not visible for BSDFs. */ - if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) { - return false; - } - /* Skip if we have no emission shaders. */ - /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll - * iterate all mesh shaders twice (when counting and when calculating - * triangle area. - */ - foreach(const Shader *shader, mesh->used_shaders) { - if(shader->use_mis && shader->has_surface_emission) { - return true; - } - } - return false; +bool LightManager::object_usable_as_light(Object *object) +{ + Mesh *mesh = object->mesh; + /* Skip objects with NaNs */ + if (!object->bounds.valid()) { + return false; + } + /* Skip if we are not visible for BSDFs. */ + if (!(object->visibility & (PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY | PATH_RAY_TRANSMIT))) { + return false; + } + /* Skip if we have no emission shaders. */ + /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll + * iterate all mesh shaders twice (when counting and when calculating + * triangle area. + */ + foreach (const Shader *shader, mesh->used_shaders) { + if (shader->use_mis && shader->has_surface_emission) { + return true; + } + } + return false; } -void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Scene *scene, Progress& progress) +void LightManager::device_update_distribution(Device *, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - progress.set_status("Updating Lights", "Computing distribution"); - - /* count */ - size_t num_lights = 0; - size_t num_portals = 0; - size_t num_background_lights = 0; - size_t num_triangles = 0; - - bool background_mis = false; - - foreach(Light *light, scene->lights) { - if(light->is_enabled) { - num_lights++; - } - if(light->is_portal) { - num_portals++; - } - } - - foreach(Object *object, scene->objects) { - if(progress.get_cancel()) return; - - if(!object_usable_as_light(object)) { - continue; - } - /* Count triangles. */ - Mesh *mesh = object->mesh; - size_t mesh_num_triangles = mesh->num_triangles(); - for(size_t i = 0; i < mesh_num_triangles; i++) { - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) - ? mesh->used_shaders[shader_index] - : scene->default_surface; - - if(shader->use_mis && shader->has_surface_emission) { - num_triangles++; - } - } - } - - size_t num_distribution = num_triangles + num_lights; - VLOG(1) << "Total " << num_distribution << " of light distribution primitives."; - - /* emission area */ - KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1); - float totarea = 0.0f; - - /* triangles */ - size_t offset = 0; - int j = 0; - - foreach(Object *object, scene->objects) { - if(progress.get_cancel()) return; - - if(!object_usable_as_light(object)) { - j++; - continue; - } - /* Sum area. */ - Mesh *mesh = object->mesh; - bool transform_applied = mesh->transform_applied; - Transform tfm = object->tfm; - int object_id = j; - int shader_flag = 0; - - if(!(object->visibility & PATH_RAY_DIFFUSE)) { - shader_flag |= SHADER_EXCLUDE_DIFFUSE; - use_light_visibility = true; - } - if(!(object->visibility & PATH_RAY_GLOSSY)) { - shader_flag |= SHADER_EXCLUDE_GLOSSY; - use_light_visibility = true; - } - if(!(object->visibility & PATH_RAY_TRANSMIT)) { - shader_flag |= SHADER_EXCLUDE_TRANSMIT; - use_light_visibility = true; - } - if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) { - shader_flag |= SHADER_EXCLUDE_SCATTER; - use_light_visibility = true; - } - - size_t mesh_num_triangles = mesh->num_triangles(); - for(size_t i = 0; i < mesh_num_triangles; i++) { - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) - ? mesh->used_shaders[shader_index] - : scene->default_surface; - - if(shader->use_mis && shader->has_surface_emission) { - distribution[offset].totarea = totarea; - distribution[offset].prim = i + mesh->tri_offset; - distribution[offset].mesh_light.shader_flag = shader_flag; - distribution[offset].mesh_light.object_id = object_id; - offset++; - - Mesh::Triangle t = mesh->get_triangle(i); - if(!t.valid(&mesh->verts[0])) { - continue; - } - float3 p1 = mesh->verts[t.v[0]]; - float3 p2 = mesh->verts[t.v[1]]; - float3 p3 = mesh->verts[t.v[2]]; - - if(!transform_applied) { - p1 = transform_point(&tfm, p1); - p2 = transform_point(&tfm, p2); - p3 = transform_point(&tfm, p3); - } - - totarea += triangle_area(p1, p2, p3); - } - } - - j++; - } - - float trianglearea = totarea; - - /* point lights */ - float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f; - bool use_lamp_mis = false; - - int light_index = 0; - foreach(Light *light, scene->lights) { - if(!light->is_enabled) - continue; - - distribution[offset].totarea = totarea; - distribution[offset].prim = ~light_index; - distribution[offset].lamp.pad = 1.0f; - distribution[offset].lamp.size = light->size; - totarea += lightarea; - - if(light->size > 0.0f && light->use_mis) - use_lamp_mis = true; - if(light->type == LIGHT_BACKGROUND) { - num_background_lights++; - background_mis = light->use_mis; - } - - light_index++; - offset++; - } - - /* normalize cumulative distribution functions */ - distribution[num_distribution].totarea = totarea; - distribution[num_distribution].prim = 0.0f; - distribution[num_distribution].lamp.pad = 0.0f; - distribution[num_distribution].lamp.size = 0.0f; - - if(totarea > 0.0f) { - for(size_t i = 0; i < num_distribution; i++) - distribution[i].totarea /= totarea; - distribution[num_distribution].totarea = 1.0f; - } - - if(progress.get_cancel()) return; - - /* update device */ - KernelIntegrator *kintegrator = &dscene->data.integrator; - KernelFilm *kfilm = &dscene->data.film; - kintegrator->use_direct_light = (totarea > 0.0f); - - if(kintegrator->use_direct_light) { - /* number of emissives */ - kintegrator->num_distribution = num_distribution; - - /* precompute pdfs */ - kintegrator->pdf_triangles = 0.0f; - kintegrator->pdf_lights = 0.0f; - - /* sample one, with 0.5 probability of light or triangle */ - kintegrator->num_all_lights = num_lights; - - if(trianglearea > 0.0f) { - kintegrator->pdf_triangles = 1.0f/trianglearea; - if(num_lights) - kintegrator->pdf_triangles *= 0.5f; - } - - if(num_lights) { - kintegrator->pdf_lights = 1.0f/num_lights; - if(trianglearea > 0.0f) - kintegrator->pdf_lights *= 0.5f; - } - - kintegrator->use_lamp_mis = use_lamp_mis; - - /* bit of an ugly hack to compensate for emitting triangles influencing - * amount of samples we get for this pass */ - kfilm->pass_shadow_scale = 1.0f; - - if(kintegrator->pdf_triangles != 0.0f) - kfilm->pass_shadow_scale *= 0.5f; - - if(num_background_lights < num_lights) - kfilm->pass_shadow_scale *= (float)(num_lights - num_background_lights)/(float)num_lights; - - /* CDF */ - dscene->light_distribution.copy_to_device(); - - /* Portals */ - if(num_portals > 0) { - kintegrator->portal_offset = light_index; - kintegrator->num_portals = num_portals; - kintegrator->portal_pdf = background_mis? 0.5f: 1.0f; - } - else { - kintegrator->num_portals = 0; - kintegrator->portal_offset = 0; - kintegrator->portal_pdf = 0.0f; - } - } - else { - dscene->light_distribution.free(); - - kintegrator->num_distribution = 0; - kintegrator->num_all_lights = 0; - kintegrator->pdf_triangles = 0.0f; - kintegrator->pdf_lights = 0.0f; - kintegrator->use_lamp_mis = false; - kintegrator->num_portals = 0; - kintegrator->portal_offset = 0; - kintegrator->portal_pdf = 0.0f; - - kfilm->pass_shadow_scale = 1.0f; - } + progress.set_status("Updating Lights", "Computing distribution"); + + /* count */ + size_t num_lights = 0; + size_t num_portals = 0; + size_t num_background_lights = 0; + size_t num_triangles = 0; + + bool background_mis = false; + + foreach (Light *light, scene->lights) { + if (light->is_enabled) { + num_lights++; + } + if (light->is_portal) { + num_portals++; + } + } + + foreach (Object *object, scene->objects) { + if (progress.get_cancel()) + return; + + if (!object_usable_as_light(object)) { + continue; + } + /* Count triangles. */ + Mesh *mesh = object->mesh; + size_t mesh_num_triangles = mesh->num_triangles(); + for (size_t i = 0; i < mesh_num_triangles; i++) { + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) ? + mesh->used_shaders[shader_index] : + scene->default_surface; + + if (shader->use_mis && shader->has_surface_emission) { + num_triangles++; + } + } + } + + size_t num_distribution = num_triangles + num_lights; + VLOG(1) << "Total " << num_distribution << " of light distribution primitives."; + + /* emission area */ + KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1); + float totarea = 0.0f; + + /* triangles */ + size_t offset = 0; + int j = 0; + + foreach (Object *object, scene->objects) { + if (progress.get_cancel()) + return; + + if (!object_usable_as_light(object)) { + j++; + continue; + } + /* Sum area. */ + Mesh *mesh = object->mesh; + bool transform_applied = mesh->transform_applied; + Transform tfm = object->tfm; + int object_id = j; + int shader_flag = 0; + + if (!(object->visibility & PATH_RAY_DIFFUSE)) { + shader_flag |= SHADER_EXCLUDE_DIFFUSE; + use_light_visibility = true; + } + if (!(object->visibility & PATH_RAY_GLOSSY)) { + shader_flag |= SHADER_EXCLUDE_GLOSSY; + use_light_visibility = true; + } + if (!(object->visibility & PATH_RAY_TRANSMIT)) { + shader_flag |= SHADER_EXCLUDE_TRANSMIT; + use_light_visibility = true; + } + if (!(object->visibility & PATH_RAY_VOLUME_SCATTER)) { + shader_flag |= SHADER_EXCLUDE_SCATTER; + use_light_visibility = true; + } + + size_t mesh_num_triangles = mesh->num_triangles(); + for (size_t i = 0; i < mesh_num_triangles; i++) { + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) ? + mesh->used_shaders[shader_index] : + scene->default_surface; + + if (shader->use_mis && shader->has_surface_emission) { + distribution[offset].totarea = totarea; + distribution[offset].prim = i + mesh->tri_offset; + distribution[offset].mesh_light.shader_flag = shader_flag; + distribution[offset].mesh_light.object_id = object_id; + offset++; + + Mesh::Triangle t = mesh->get_triangle(i); + if (!t.valid(&mesh->verts[0])) { + continue; + } + float3 p1 = mesh->verts[t.v[0]]; + float3 p2 = mesh->verts[t.v[1]]; + float3 p3 = mesh->verts[t.v[2]]; + + if (!transform_applied) { + p1 = transform_point(&tfm, p1); + p2 = transform_point(&tfm, p2); + p3 = transform_point(&tfm, p3); + } + + totarea += triangle_area(p1, p2, p3); + } + } + + j++; + } + + float trianglearea = totarea; + + /* point lights */ + float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f; + bool use_lamp_mis = false; + + int light_index = 0; + foreach (Light *light, scene->lights) { + if (!light->is_enabled) + continue; + + distribution[offset].totarea = totarea; + distribution[offset].prim = ~light_index; + distribution[offset].lamp.pad = 1.0f; + distribution[offset].lamp.size = light->size; + totarea += lightarea; + + if (light->size > 0.0f && light->use_mis) + use_lamp_mis = true; + if (light->type == LIGHT_BACKGROUND) { + num_background_lights++; + background_mis = light->use_mis; + } + + light_index++; + offset++; + } + + /* normalize cumulative distribution functions */ + distribution[num_distribution].totarea = totarea; + distribution[num_distribution].prim = 0.0f; + distribution[num_distribution].lamp.pad = 0.0f; + distribution[num_distribution].lamp.size = 0.0f; + + if (totarea > 0.0f) { + for (size_t i = 0; i < num_distribution; i++) + distribution[i].totarea /= totarea; + distribution[num_distribution].totarea = 1.0f; + } + + if (progress.get_cancel()) + return; + + /* update device */ + KernelIntegrator *kintegrator = &dscene->data.integrator; + KernelFilm *kfilm = &dscene->data.film; + kintegrator->use_direct_light = (totarea > 0.0f); + + if (kintegrator->use_direct_light) { + /* number of emissives */ + kintegrator->num_distribution = num_distribution; + + /* precompute pdfs */ + kintegrator->pdf_triangles = 0.0f; + kintegrator->pdf_lights = 0.0f; + + /* sample one, with 0.5 probability of light or triangle */ + kintegrator->num_all_lights = num_lights; + + if (trianglearea > 0.0f) { + kintegrator->pdf_triangles = 1.0f / trianglearea; + if (num_lights) + kintegrator->pdf_triangles *= 0.5f; + } + + if (num_lights) { + kintegrator->pdf_lights = 1.0f / num_lights; + if (trianglearea > 0.0f) + kintegrator->pdf_lights *= 0.5f; + } + + kintegrator->use_lamp_mis = use_lamp_mis; + + /* bit of an ugly hack to compensate for emitting triangles influencing + * amount of samples we get for this pass */ + kfilm->pass_shadow_scale = 1.0f; + + if (kintegrator->pdf_triangles != 0.0f) + kfilm->pass_shadow_scale *= 0.5f; + + if (num_background_lights < num_lights) + kfilm->pass_shadow_scale *= (float)(num_lights - num_background_lights) / (float)num_lights; + + /* CDF */ + dscene->light_distribution.copy_to_device(); + + /* Portals */ + if (num_portals > 0) { + kintegrator->portal_offset = light_index; + kintegrator->num_portals = num_portals; + kintegrator->portal_pdf = background_mis ? 0.5f : 1.0f; + } + else { + kintegrator->num_portals = 0; + kintegrator->portal_offset = 0; + kintegrator->portal_pdf = 0.0f; + } + } + else { + dscene->light_distribution.free(); + + kintegrator->num_distribution = 0; + kintegrator->num_all_lights = 0; + kintegrator->pdf_triangles = 0.0f; + kintegrator->pdf_lights = 0.0f; + kintegrator->use_lamp_mis = false; + kintegrator->num_portals = 0; + kintegrator->portal_offset = 0; + kintegrator->portal_pdf = 0.0f; + + kfilm->pass_shadow_scale = 1.0f; + } } -static void background_cdf(int start, - int end, - int res_x, - int res_y, - const vector<float3> *pixels, - float2 *cond_cdf) +static void background_cdf( + int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf) { - int cdf_width = res_x+1; - /* Conditional CDFs (rows, U direction). */ - for(int i = start; i < end; i++) { - float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y); - float3 env_color = (*pixels)[i * res_x]; - float ave_luminance = average(env_color); - - cond_cdf[i * cdf_width].x = ave_luminance * sin_theta; - cond_cdf[i * cdf_width].y = 0.0f; - - for(int j = 1; j < res_x; j++) { - env_color = (*pixels)[i * res_x + j]; - ave_luminance = average(env_color); - - cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta; - cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y + cond_cdf[i * cdf_width + j - 1].x / res_x; - } - - float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y + cond_cdf[i * cdf_width + res_x - 1].x / res_x; - float cdf_total_inv = 1.0f / cdf_total; - - /* stuff the total into the brightness value for the last entry, because - * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */ - cond_cdf[i * cdf_width + res_x].x = cdf_total; - - if(cdf_total > 0.0f) - for(int j = 1; j < res_x; j++) - cond_cdf[i * cdf_width + j].y *= cdf_total_inv; - - cond_cdf[i * cdf_width + res_x].y = 1.0f; - } + int cdf_width = res_x + 1; + /* Conditional CDFs (rows, U direction). */ + for (int i = start; i < end; i++) { + float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y); + float3 env_color = (*pixels)[i * res_x]; + float ave_luminance = average(env_color); + + cond_cdf[i * cdf_width].x = ave_luminance * sin_theta; + cond_cdf[i * cdf_width].y = 0.0f; + + for (int j = 1; j < res_x; j++) { + env_color = (*pixels)[i * res_x + j]; + ave_luminance = average(env_color); + + cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta; + cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y + + cond_cdf[i * cdf_width + j - 1].x / res_x; + } + + float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y + + cond_cdf[i * cdf_width + res_x - 1].x / res_x; + float cdf_total_inv = 1.0f / cdf_total; + + /* stuff the total into the brightness value for the last entry, because + * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */ + cond_cdf[i * cdf_width + res_x].x = cdf_total; + + if (cdf_total > 0.0f) + for (int j = 1; j < res_x; j++) + cond_cdf[i * cdf_width + j].y *= cdf_total_inv; + + cond_cdf[i * cdf_width + res_x].y = 1.0f; + } } void LightManager::device_update_background(Device *device, DeviceScene *dscene, Scene *scene, - Progress& progress) + Progress &progress) { - KernelIntegrator *kintegrator = &dscene->data.integrator; - Light *background_light = NULL; - - /* find background light */ - foreach(Light *light, scene->lights) { - if(light->type == LIGHT_BACKGROUND) { - background_light = light; - break; - } - } - - /* no background light found, signal renderer to skip sampling */ - if(!background_light || !background_light->is_enabled) { - kintegrator->pdf_background_res_x = 0; - kintegrator->pdf_background_res_y = 0; - return; - } - - progress.set_status("Updating Lights", "Importance map"); - - assert(kintegrator->use_direct_light); - - /* get the resolution from the light's size (we stuff it in there) */ - int2 res = make_int2(background_light->map_resolution, background_light->map_resolution/2); - /* If the resolution isn't set manually, try to find an environment texture. */ - if(res.x == 0) { - Shader *shader = (scene->background->shader) ? scene->background->shader : scene->default_background; - foreach(ShaderNode *node, shader->graph->nodes) { - if(node->type == EnvironmentTextureNode::node_type) { - EnvironmentTextureNode *env = (EnvironmentTextureNode*) node; - ImageMetaData metadata; - if(env->image_manager && env->image_manager->get_image_metadata(env->slot, metadata)) { - res.x = max(res.x, metadata.width); - res.y = max(res.y, metadata.height); - } - } - } - if(res.x > 0 && res.y > 0) { - VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n"; - } - } - /* If it's still unknown, just use the default. */ - if(res.x == 0 || res.y == 0) { - res = make_int2(1024, 512); - VLOG(2) << "Setting World MIS resolution to default\n"; - } - kintegrator->pdf_background_res_x = res.x; - kintegrator->pdf_background_res_y = res.y; - - vector<float3> pixels; - shade_background_pixels(device, dscene, res.x, res.y, pixels, progress); - - if(progress.get_cancel()) - return; - - /* build row distributions and column distribution for the infinite area environment light */ - int cdf_width = res.x+1; - float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1); - float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y); - - double time_start = time_dt(); - if(max(res.x, res.y) < 512) { - /* Small enough resolution, faster to do single-threaded. */ - background_cdf(0, res.y, res.x, res.y, &pixels, cond_cdf); - } - else { - /* Threaded evaluation for large resolution. */ - const int num_blocks = TaskScheduler::num_threads(); - const int chunk_size = res.y / num_blocks; - int start_row = 0; - TaskPool pool; - for(int i = 0; i < num_blocks; ++i) { - const int current_chunk_size = - (i != num_blocks - 1) ? chunk_size - : (res.y - i * chunk_size); - pool.push(function_bind(&background_cdf, - start_row, start_row + current_chunk_size, - res.x, - res.y, - &pixels, - cond_cdf)); - start_row += current_chunk_size; - } - pool.wait_work(); - } - - /* marginal CDFs (column, V direction, sum of rows) */ - marg_cdf[0].x = cond_cdf[res.x].x; - marg_cdf[0].y = 0.0f; - - for(int i = 1; i < res.y; i++) { - marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x; - marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y; - } - - float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y; - marg_cdf[res.y].x = cdf_total; - - if(cdf_total > 0.0f) - for(int i = 1; i < res.y; i++) - marg_cdf[i].y /= cdf_total; - - marg_cdf[res.y].y = 1.0f; - - VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n"; - - /* update device */ - dscene->light_background_marginal_cdf.copy_to_device(); - dscene->light_background_conditional_cdf.copy_to_device(); + KernelIntegrator *kintegrator = &dscene->data.integrator; + Light *background_light = NULL; + + /* find background light */ + foreach (Light *light, scene->lights) { + if (light->type == LIGHT_BACKGROUND) { + background_light = light; + break; + } + } + + /* no background light found, signal renderer to skip sampling */ + if (!background_light || !background_light->is_enabled) { + kintegrator->pdf_background_res_x = 0; + kintegrator->pdf_background_res_y = 0; + return; + } + + progress.set_status("Updating Lights", "Importance map"); + + assert(kintegrator->use_direct_light); + + /* get the resolution from the light's size (we stuff it in there) */ + int2 res = make_int2(background_light->map_resolution, background_light->map_resolution / 2); + /* If the resolution isn't set manually, try to find an environment texture. */ + if (res.x == 0) { + Shader *shader = (scene->background->shader) ? scene->background->shader : + scene->default_background; + foreach (ShaderNode *node, shader->graph->nodes) { + if (node->type == EnvironmentTextureNode::node_type) { + EnvironmentTextureNode *env = (EnvironmentTextureNode *)node; + ImageMetaData metadata; + if (env->image_manager && env->image_manager->get_image_metadata(env->slot, metadata)) { + res.x = max(res.x, metadata.width); + res.y = max(res.y, metadata.height); + } + } + } + if (res.x > 0 && res.y > 0) { + VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n"; + } + } + /* If it's still unknown, just use the default. */ + if (res.x == 0 || res.y == 0) { + res = make_int2(1024, 512); + VLOG(2) << "Setting World MIS resolution to default\n"; + } + kintegrator->pdf_background_res_x = res.x; + kintegrator->pdf_background_res_y = res.y; + + vector<float3> pixels; + shade_background_pixels(device, dscene, res.x, res.y, pixels, progress); + + if (progress.get_cancel()) + return; + + /* build row distributions and column distribution for the infinite area environment light */ + int cdf_width = res.x + 1; + float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1); + float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y); + + double time_start = time_dt(); + if (max(res.x, res.y) < 512) { + /* Small enough resolution, faster to do single-threaded. */ + background_cdf(0, res.y, res.x, res.y, &pixels, cond_cdf); + } + else { + /* Threaded evaluation for large resolution. */ + const int num_blocks = TaskScheduler::num_threads(); + const int chunk_size = res.y / num_blocks; + int start_row = 0; + TaskPool pool; + for (int i = 0; i < num_blocks; ++i) { + const int current_chunk_size = (i != num_blocks - 1) ? chunk_size : (res.y - i * chunk_size); + pool.push(function_bind(&background_cdf, + start_row, + start_row + current_chunk_size, + res.x, + res.y, + &pixels, + cond_cdf)); + start_row += current_chunk_size; + } + pool.wait_work(); + } + + /* marginal CDFs (column, V direction, sum of rows) */ + marg_cdf[0].x = cond_cdf[res.x].x; + marg_cdf[0].y = 0.0f; + + for (int i = 1; i < res.y; i++) { + marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x; + marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y; + } + + float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y; + marg_cdf[res.y].x = cdf_total; + + if (cdf_total > 0.0f) + for (int i = 1; i < res.y; i++) + marg_cdf[i].y /= cdf_total; + + marg_cdf[res.y].y = 1.0f; + + VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n"; + + /* update device */ + dscene->light_background_marginal_cdf.copy_to_device(); + dscene->light_background_conditional_cdf.copy_to_device(); } -void LightManager::device_update_points(Device *, - DeviceScene *dscene, - Scene *scene) +void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *scene) { - int num_scene_lights = scene->lights.size(); - - int num_lights = 0; - foreach(Light *light, scene->lights) { - if(light->is_enabled || light->is_portal) { - num_lights++; - } - } - - KernelLight *klights = dscene->lights.alloc(num_lights); - - if(num_lights == 0) { - VLOG(1) << "No effective light, ignoring points update."; - return; - } - - int light_index = 0; - - foreach(Light *light, scene->lights) { - if(!light->is_enabled) { - continue; - } - - float3 co = light->co; - Shader *shader = (light->shader) ? light->shader : scene->default_light; - int shader_id = scene->shader_manager->get_shader_id(shader); - int samples = light->samples; - int max_bounces = light->max_bounces; - float random = (float)light->random_id * (1.0f/(float)0xFFFFFFFF); - - if(!light->cast_shadow) - shader_id &= ~SHADER_CAST_SHADOW; - - if(!light->use_diffuse) { - shader_id |= SHADER_EXCLUDE_DIFFUSE; - use_light_visibility = true; - } - if(!light->use_glossy) { - shader_id |= SHADER_EXCLUDE_GLOSSY; - use_light_visibility = true; - } - if(!light->use_transmission) { - shader_id |= SHADER_EXCLUDE_TRANSMIT; - use_light_visibility = true; - } - if(!light->use_scatter) { - shader_id |= SHADER_EXCLUDE_SCATTER; - use_light_visibility = true; - } - - klights[light_index].type = light->type; - klights[light_index].samples = samples; - - if(light->type == LIGHT_POINT) { - shader_id &= ~SHADER_AREA_LIGHT; - - float radius = light->size; - float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f; - - if(light->use_mis && radius > 0.0f) - shader_id |= SHADER_USE_MIS; - - klights[light_index].co[0] = co.x; - klights[light_index].co[1] = co.y; - klights[light_index].co[2] = co.z; - - klights[light_index].spot.radius = radius; - klights[light_index].spot.invarea = invarea; - } - else if(light->type == LIGHT_DISTANT) { - shader_id &= ~SHADER_AREA_LIGHT; - - float radius = light->size; - float angle = atanf(radius); - float cosangle = cosf(angle); - float area = M_PI_F*radius*radius; - float invarea = (area > 0.0f)? 1.0f/area: 1.0f; - float3 dir = light->dir; - - dir = safe_normalize(dir); - - if(light->use_mis && area > 0.0f) - shader_id |= SHADER_USE_MIS; - - klights[light_index].co[0] = dir.x; - klights[light_index].co[1] = dir.y; - klights[light_index].co[2] = dir.z; - - klights[light_index].distant.invarea = invarea; - klights[light_index].distant.radius = radius; - klights[light_index].distant.cosangle = cosangle; - } - else if(light->type == LIGHT_BACKGROUND) { - uint visibility = scene->background->visibility; - - shader_id &= ~SHADER_AREA_LIGHT; - shader_id |= SHADER_USE_MIS; - - if(!(visibility & PATH_RAY_DIFFUSE)) { - shader_id |= SHADER_EXCLUDE_DIFFUSE; - use_light_visibility = true; - } - if(!(visibility & PATH_RAY_GLOSSY)) { - shader_id |= SHADER_EXCLUDE_GLOSSY; - use_light_visibility = true; - } - if(!(visibility & PATH_RAY_TRANSMIT)) { - shader_id |= SHADER_EXCLUDE_TRANSMIT; - use_light_visibility = true; - } - if(!(visibility & PATH_RAY_VOLUME_SCATTER)) { - shader_id |= SHADER_EXCLUDE_SCATTER; - use_light_visibility = true; - } - } - else if(light->type == LIGHT_AREA) { - float3 axisu = light->axisu*(light->sizeu*light->size); - float3 axisv = light->axisv*(light->sizev*light->size); - float area = len(axisu)*len(axisv); - if(light->round) { - area *= -M_PI_4_F; - } - float invarea = (area != 0.0f)? 1.0f/area: 1.0f; - float3 dir = light->dir; - - dir = safe_normalize(dir); - - if(light->use_mis && area != 0.0f) - shader_id |= SHADER_USE_MIS; - - klights[light_index].co[0] = co.x; - klights[light_index].co[1] = co.y; - klights[light_index].co[2] = co.z; - - klights[light_index].area.axisu[0] = axisu.x; - klights[light_index].area.axisu[1] = axisu.y; - klights[light_index].area.axisu[2] = axisu.z; - klights[light_index].area.axisv[0] = axisv.x; - klights[light_index].area.axisv[1] = axisv.y; - klights[light_index].area.axisv[2] = axisv.z; - klights[light_index].area.invarea = invarea; - klights[light_index].area.dir[0] = dir.x; - klights[light_index].area.dir[1] = dir.y; - klights[light_index].area.dir[2] = dir.z; - } - else if(light->type == LIGHT_SPOT) { - shader_id &= ~SHADER_AREA_LIGHT; - - float radius = light->size; - float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f; - float spot_angle = cosf(light->spot_angle*0.5f); - float spot_smooth = (1.0f - spot_angle)*light->spot_smooth; - float3 dir = light->dir; - - dir = safe_normalize(dir); - - if(light->use_mis && radius > 0.0f) - shader_id |= SHADER_USE_MIS; - - klights[light_index].co[0] = co.x; - klights[light_index].co[1] = co.y; - klights[light_index].co[2] = co.z; - - klights[light_index].spot.radius = radius; - klights[light_index].spot.invarea = invarea; - klights[light_index].spot.spot_angle = spot_angle; - klights[light_index].spot.spot_smooth = spot_smooth; - klights[light_index].spot.dir[0] = dir.x; - klights[light_index].spot.dir[1] = dir.y; - klights[light_index].spot.dir[2] = dir.z; - } - - klights[light_index].shader_id = shader_id; - - klights[light_index].max_bounces = max_bounces; - klights[light_index].random = random; - - klights[light_index].tfm = light->tfm; - klights[light_index].itfm = transform_inverse(light->tfm); - - light_index++; - } - - /* TODO(sergey): Consider moving portals update to their own function - * keeping this one more manageable. - */ - foreach(Light *light, scene->lights) { - if(!light->is_portal) - continue; - assert(light->type == LIGHT_AREA); - - float3 co = light->co; - float3 axisu = light->axisu*(light->sizeu*light->size); - float3 axisv = light->axisv*(light->sizev*light->size); - float area = len(axisu)*len(axisv); - if(light->round) { - area *= -M_PI_4_F; - } - float invarea = (area != 0.0f)? 1.0f/area: 1.0f; - float3 dir = light->dir; - - dir = safe_normalize(dir); - - klights[light_index].co[0] = co.x; - klights[light_index].co[1] = co.y; - klights[light_index].co[2] = co.z; - - klights[light_index].area.axisu[0] = axisu.x; - klights[light_index].area.axisu[1] = axisu.y; - klights[light_index].area.axisu[2] = axisu.z; - klights[light_index].area.axisv[0] = axisv.x; - klights[light_index].area.axisv[1] = axisv.y; - klights[light_index].area.axisv[2] = axisv.z; - klights[light_index].area.invarea = invarea; - klights[light_index].area.dir[0] = dir.x; - klights[light_index].area.dir[1] = dir.y; - klights[light_index].area.dir[2] = dir.z; - klights[light_index].tfm = light->tfm; - klights[light_index].itfm = transform_inverse(light->tfm); - - light_index++; - } - - VLOG(1) << "Number of lights sent to the device: " << light_index; - - VLOG(1) << "Number of lights without contribution: " - << num_scene_lights - light_index; - - dscene->lights.copy_to_device(); + int num_scene_lights = scene->lights.size(); + + int num_lights = 0; + foreach (Light *light, scene->lights) { + if (light->is_enabled || light->is_portal) { + num_lights++; + } + } + + KernelLight *klights = dscene->lights.alloc(num_lights); + + if (num_lights == 0) { + VLOG(1) << "No effective light, ignoring points update."; + return; + } + + int light_index = 0; + + foreach (Light *light, scene->lights) { + if (!light->is_enabled) { + continue; + } + + float3 co = light->co; + Shader *shader = (light->shader) ? light->shader : scene->default_light; + int shader_id = scene->shader_manager->get_shader_id(shader); + int samples = light->samples; + int max_bounces = light->max_bounces; + float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF); + + if (!light->cast_shadow) + shader_id &= ~SHADER_CAST_SHADOW; + + if (!light->use_diffuse) { + shader_id |= SHADER_EXCLUDE_DIFFUSE; + use_light_visibility = true; + } + if (!light->use_glossy) { + shader_id |= SHADER_EXCLUDE_GLOSSY; + use_light_visibility = true; + } + if (!light->use_transmission) { + shader_id |= SHADER_EXCLUDE_TRANSMIT; + use_light_visibility = true; + } + if (!light->use_scatter) { + shader_id |= SHADER_EXCLUDE_SCATTER; + use_light_visibility = true; + } + + klights[light_index].type = light->type; + klights[light_index].samples = samples; + + if (light->type == LIGHT_POINT) { + shader_id &= ~SHADER_AREA_LIGHT; + + float radius = light->size; + float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; + + if (light->use_mis && radius > 0.0f) + shader_id |= SHADER_USE_MIS; + + klights[light_index].co[0] = co.x; + klights[light_index].co[1] = co.y; + klights[light_index].co[2] = co.z; + + klights[light_index].spot.radius = radius; + klights[light_index].spot.invarea = invarea; + } + else if (light->type == LIGHT_DISTANT) { + shader_id &= ~SHADER_AREA_LIGHT; + + float radius = light->size; + float angle = atanf(radius); + float cosangle = cosf(angle); + float area = M_PI_F * radius * radius; + float invarea = (area > 0.0f) ? 1.0f / area : 1.0f; + float3 dir = light->dir; + + dir = safe_normalize(dir); + + if (light->use_mis && area > 0.0f) + shader_id |= SHADER_USE_MIS; + + klights[light_index].co[0] = dir.x; + klights[light_index].co[1] = dir.y; + klights[light_index].co[2] = dir.z; + + klights[light_index].distant.invarea = invarea; + klights[light_index].distant.radius = radius; + klights[light_index].distant.cosangle = cosangle; + } + else if (light->type == LIGHT_BACKGROUND) { + uint visibility = scene->background->visibility; + + shader_id &= ~SHADER_AREA_LIGHT; + shader_id |= SHADER_USE_MIS; + + if (!(visibility & PATH_RAY_DIFFUSE)) { + shader_id |= SHADER_EXCLUDE_DIFFUSE; + use_light_visibility = true; + } + if (!(visibility & PATH_RAY_GLOSSY)) { + shader_id |= SHADER_EXCLUDE_GLOSSY; + use_light_visibility = true; + } + if (!(visibility & PATH_RAY_TRANSMIT)) { + shader_id |= SHADER_EXCLUDE_TRANSMIT; + use_light_visibility = true; + } + if (!(visibility & PATH_RAY_VOLUME_SCATTER)) { + shader_id |= SHADER_EXCLUDE_SCATTER; + use_light_visibility = true; + } + } + else if (light->type == LIGHT_AREA) { + float3 axisu = light->axisu * (light->sizeu * light->size); + float3 axisv = light->axisv * (light->sizev * light->size); + float area = len(axisu) * len(axisv); + if (light->round) { + area *= -M_PI_4_F; + } + float invarea = (area != 0.0f) ? 1.0f / area : 1.0f; + float3 dir = light->dir; + + dir = safe_normalize(dir); + + if (light->use_mis && area != 0.0f) + shader_id |= SHADER_USE_MIS; + + klights[light_index].co[0] = co.x; + klights[light_index].co[1] = co.y; + klights[light_index].co[2] = co.z; + + klights[light_index].area.axisu[0] = axisu.x; + klights[light_index].area.axisu[1] = axisu.y; + klights[light_index].area.axisu[2] = axisu.z; + klights[light_index].area.axisv[0] = axisv.x; + klights[light_index].area.axisv[1] = axisv.y; + klights[light_index].area.axisv[2] = axisv.z; + klights[light_index].area.invarea = invarea; + klights[light_index].area.dir[0] = dir.x; + klights[light_index].area.dir[1] = dir.y; + klights[light_index].area.dir[2] = dir.z; + } + else if (light->type == LIGHT_SPOT) { + shader_id &= ~SHADER_AREA_LIGHT; + + float radius = light->size; + float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; + float spot_angle = cosf(light->spot_angle * 0.5f); + float spot_smooth = (1.0f - spot_angle) * light->spot_smooth; + float3 dir = light->dir; + + dir = safe_normalize(dir); + + if (light->use_mis && radius > 0.0f) + shader_id |= SHADER_USE_MIS; + + klights[light_index].co[0] = co.x; + klights[light_index].co[1] = co.y; + klights[light_index].co[2] = co.z; + + klights[light_index].spot.radius = radius; + klights[light_index].spot.invarea = invarea; + klights[light_index].spot.spot_angle = spot_angle; + klights[light_index].spot.spot_smooth = spot_smooth; + klights[light_index].spot.dir[0] = dir.x; + klights[light_index].spot.dir[1] = dir.y; + klights[light_index].spot.dir[2] = dir.z; + } + + klights[light_index].shader_id = shader_id; + + klights[light_index].max_bounces = max_bounces; + klights[light_index].random = random; + + klights[light_index].tfm = light->tfm; + klights[light_index].itfm = transform_inverse(light->tfm); + + light_index++; + } + + /* TODO(sergey): Consider moving portals update to their own function + * keeping this one more manageable. + */ + foreach (Light *light, scene->lights) { + if (!light->is_portal) + continue; + assert(light->type == LIGHT_AREA); + + float3 co = light->co; + float3 axisu = light->axisu * (light->sizeu * light->size); + float3 axisv = light->axisv * (light->sizev * light->size); + float area = len(axisu) * len(axisv); + if (light->round) { + area *= -M_PI_4_F; + } + float invarea = (area != 0.0f) ? 1.0f / area : 1.0f; + float3 dir = light->dir; + + dir = safe_normalize(dir); + + klights[light_index].co[0] = co.x; + klights[light_index].co[1] = co.y; + klights[light_index].co[2] = co.z; + + klights[light_index].area.axisu[0] = axisu.x; + klights[light_index].area.axisu[1] = axisu.y; + klights[light_index].area.axisu[2] = axisu.z; + klights[light_index].area.axisv[0] = axisv.x; + klights[light_index].area.axisv[1] = axisv.y; + klights[light_index].area.axisv[2] = axisv.z; + klights[light_index].area.invarea = invarea; + klights[light_index].area.dir[0] = dir.x; + klights[light_index].area.dir[1] = dir.y; + klights[light_index].area.dir[2] = dir.z; + klights[light_index].tfm = light->tfm; + klights[light_index].itfm = transform_inverse(light->tfm); + + light_index++; + } + + VLOG(1) << "Number of lights sent to the device: " << light_index; + + VLOG(1) << "Number of lights without contribution: " << num_scene_lights - light_index; + + dscene->lights.copy_to_device(); } -void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void LightManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - VLOG(1) << "Total " << scene->lights.size() << " lights."; + VLOG(1) << "Total " << scene->lights.size() << " lights."; - device_free(device, dscene); + device_free(device, dscene); - use_light_visibility = false; + use_light_visibility = false; - disable_ineffective_light(scene); + disable_ineffective_light(scene); - device_update_points(device, dscene, scene); - if(progress.get_cancel()) return; + device_update_points(device, dscene, scene); + if (progress.get_cancel()) + return; - device_update_distribution(device, dscene, scene, progress); - if(progress.get_cancel()) return; + device_update_distribution(device, dscene, scene, progress); + if (progress.get_cancel()) + return; - device_update_background(device, dscene, scene, progress); - if(progress.get_cancel()) return; + device_update_background(device, dscene, scene, progress); + if (progress.get_cancel()) + return; - device_update_ies(dscene); - if(progress.get_cancel()) return; + device_update_ies(dscene); + if (progress.get_cancel()) + return; - if(use_light_visibility != scene->film->use_light_visibility) { - scene->film->use_light_visibility = use_light_visibility; - scene->film->tag_update(scene); - } + if (use_light_visibility != scene->film->use_light_visibility) { + scene->film->use_light_visibility = use_light_visibility; + scene->film->tag_update(scene); + } - need_update = false; + need_update = false; } void LightManager::device_free(Device *, DeviceScene *dscene) { - dscene->light_distribution.free(); - dscene->lights.free(); - dscene->light_background_marginal_cdf.free(); - dscene->light_background_conditional_cdf.free(); - dscene->ies_lights.free(); + dscene->light_distribution.free(); + dscene->lights.free(); + dscene->light_background_marginal_cdf.free(); + dscene->light_background_conditional_cdf.free(); + dscene->ies_lights.free(); } void LightManager::tag_update(Scene * /*scene*/) { - need_update = true; + need_update = true; } int LightManager::add_ies_from_file(ustring filename) { - string content; + string content; - /* If the file can't be opened, call with an empty line */ - if(filename.empty() || !path_read_text(filename.c_str(), content)) { - content = "\n"; - } + /* If the file can't be opened, call with an empty line */ + if (filename.empty() || !path_read_text(filename.c_str(), content)) { + content = "\n"; + } - return add_ies(ustring(content)); + return add_ies(ustring(content)); } int LightManager::add_ies(ustring content) { - uint hash = hash_string(content.c_str()); - - thread_scoped_lock ies_lock(ies_mutex); - - /* Check whether this IES already has a slot. */ - size_t slot; - for(slot = 0; slot < ies_slots.size(); slot++) { - if(ies_slots[slot]->hash == hash) { - ies_slots[slot]->users++; - return slot; - } - } - - /* Try to find an empty slot for the new IES. */ - for(slot = 0; slot < ies_slots.size(); slot++) { - if(ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) { - break; - } - } - - /* If there's no free slot, add one. */ - if(slot == ies_slots.size()) { - ies_slots.push_back(new IESSlot()); - } - - ies_slots[slot]->ies.load(content); - ies_slots[slot]->users = 1; - ies_slots[slot]->hash = hash; - - need_update = true; - - return slot; + uint hash = hash_string(content.c_str()); + + thread_scoped_lock ies_lock(ies_mutex); + + /* Check whether this IES already has a slot. */ + size_t slot; + for (slot = 0; slot < ies_slots.size(); slot++) { + if (ies_slots[slot]->hash == hash) { + ies_slots[slot]->users++; + return slot; + } + } + + /* Try to find an empty slot for the new IES. */ + for (slot = 0; slot < ies_slots.size(); slot++) { + if (ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) { + break; + } + } + + /* If there's no free slot, add one. */ + if (slot == ies_slots.size()) { + ies_slots.push_back(new IESSlot()); + } + + ies_slots[slot]->ies.load(content); + ies_slots[slot]->users = 1; + ies_slots[slot]->hash = hash; + + need_update = true; + + return slot; } void LightManager::remove_ies(int slot) { - thread_scoped_lock ies_lock(ies_mutex); + thread_scoped_lock ies_lock(ies_mutex); - if(slot < 0 || slot >= ies_slots.size()) { - assert(false); - return; - } + if (slot < 0 || slot >= ies_slots.size()) { + assert(false); + return; + } - assert(ies_slots[slot]->users > 0); - ies_slots[slot]->users--; + assert(ies_slots[slot]->users > 0); + ies_slots[slot]->users--; - /* If the slot has no more users, update the device to remove it. */ - need_update |= (ies_slots[slot]->users == 0); + /* If the slot has no more users, update the device to remove it. */ + need_update |= (ies_slots[slot]->users == 0); } void LightManager::device_update_ies(DeviceScene *dscene) { - /* Clear empty slots. */ - foreach(IESSlot *slot, ies_slots) { - if(slot->users == 0) { - slot->hash = 0; - slot->ies.clear(); - } - } - - /* Shrink the slot table by removing empty slots at the end. */ - int slot_end; - for(slot_end = ies_slots.size(); slot_end; slot_end--) { - if(ies_slots[slot_end-1]->users > 0) { - /* If the preceding slot has users, we found the new end of the table. */ - break; - } - else { - /* The slot will be past the new end of the table, so free it. */ - delete ies_slots[slot_end-1]; - } - } - ies_slots.resize(slot_end); - - if(ies_slots.size() > 0) { - int packed_size = 0; - foreach(IESSlot *slot, ies_slots) { - packed_size += slot->ies.packed_size(); - } - - /* ies_lights starts with an offset table that contains the offset of every slot, - * or -1 if the slot is invalid. - * Following that table, the packed valid IES lights are stored. */ - float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size); - - int offset = ies_slots.size(); - for(int i = 0; i < ies_slots.size(); i++) { - int size = ies_slots[i]->ies.packed_size(); - if(size > 0) { - data[i] = __int_as_float(offset); - ies_slots[i]->ies.pack(data + offset); - offset += size; - } - else { - data[i] = __int_as_float(-1); - } - } - - dscene->ies_lights.copy_to_device(); - } + /* Clear empty slots. */ + foreach (IESSlot *slot, ies_slots) { + if (slot->users == 0) { + slot->hash = 0; + slot->ies.clear(); + } + } + + /* Shrink the slot table by removing empty slots at the end. */ + int slot_end; + for (slot_end = ies_slots.size(); slot_end; slot_end--) { + if (ies_slots[slot_end - 1]->users > 0) { + /* If the preceding slot has users, we found the new end of the table. */ + break; + } + else { + /* The slot will be past the new end of the table, so free it. */ + delete ies_slots[slot_end - 1]; + } + } + ies_slots.resize(slot_end); + + if (ies_slots.size() > 0) { + int packed_size = 0; + foreach (IESSlot *slot, ies_slots) { + packed_size += slot->ies.packed_size(); + } + + /* ies_lights starts with an offset table that contains the offset of every slot, + * or -1 if the slot is invalid. + * Following that table, the packed valid IES lights are stored. */ + float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size); + + int offset = ies_slots.size(); + for (int i = 0; i < ies_slots.size(); i++) { + int size = ies_slots[i]->ies.packed_size(); + if (size > 0) { + data[i] = __int_as_float(offset); + ies_slots[i]->ies.pack(data + offset); + offset += size; + } + else { + data[i] = __int_as_float(-1); + } + } + + dscene->ies_lights.copy_to_device(); + } } CCL_NAMESPACE_END diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index a627ec9bdc3..66732000f3b 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -36,108 +36,103 @@ class Scene; class Shader; class Light : public Node { -public: - NODE_DECLARE; + public: + NODE_DECLARE; - Light(); + Light(); - LightType type; - float3 co; + LightType type; + float3 co; - float3 dir; - float size; + float3 dir; + float size; - float3 axisu; - float sizeu; - float3 axisv; - float sizev; - bool round; + float3 axisu; + float sizeu; + float3 axisv; + float sizev; + bool round; - Transform tfm; + Transform tfm; - int map_resolution; + int map_resolution; - float spot_angle; - float spot_smooth; + float spot_angle; + float spot_smooth; - bool cast_shadow; - bool use_mis; - bool use_diffuse; - bool use_glossy; - bool use_transmission; - bool use_scatter; + bool cast_shadow; + bool use_mis; + bool use_diffuse; + bool use_glossy; + bool use_transmission; + bool use_scatter; - bool is_portal; - bool is_enabled; + bool is_portal; + bool is_enabled; - Shader *shader; - int samples; - int max_bounces; - uint random_id; + Shader *shader; + int samples; + int max_bounces; + uint random_id; - void tag_update(Scene *scene); + void tag_update(Scene *scene); - /* Check whether the light has contribution the the scene. */ - bool has_contribution(Scene *scene); + /* Check whether the light has contribution the the scene. */ + bool has_contribution(Scene *scene); }; class LightManager { -public: - bool use_light_visibility; - bool need_update; - - LightManager(); - ~LightManager(); - - /* IES texture management */ - int add_ies(ustring ies); - int add_ies_from_file(ustring filename); - void remove_ies(int slot); - - void device_update(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress); - void device_free(Device *device, DeviceScene *dscene); - - void tag_update(Scene *scene); - - /* Check whether there is a background light. */ - bool has_background_light(Scene *scene); - -protected: - /* Optimization: disable light which is either unsupported or - * which doesn't contribute to the scene or which is only used for MIS - * and scene doesn't need MIS. - */ - void disable_ineffective_light(Scene *scene); - - void device_update_points(Device *device, - DeviceScene *dscene, - Scene *scene); - void device_update_distribution(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress); - void device_update_background(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress); - void device_update_ies(DeviceScene *dscene); - - /* Check whether light manager can use the object as a light-emissive. */ - bool object_usable_as_light(Object *object); - - struct IESSlot { - IESFile ies; - uint hash; - int users; - }; - - vector<IESSlot*> ies_slots; - thread_mutex ies_mutex; + public: + bool use_light_visibility; + bool need_update; + + LightManager(); + ~LightManager(); + + /* IES texture management */ + int add_ies(ustring ies); + int add_ies_from_file(ustring filename); + void remove_ies(int slot); + + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free(Device *device, DeviceScene *dscene); + + void tag_update(Scene *scene); + + /* Check whether there is a background light. */ + bool has_background_light(Scene *scene); + + protected: + /* Optimization: disable light which is either unsupported or + * which doesn't contribute to the scene or which is only used for MIS + * and scene doesn't need MIS. + */ + void disable_ineffective_light(Scene *scene); + + void device_update_points(Device *device, DeviceScene *dscene, Scene *scene); + void device_update_distribution(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress); + void device_update_background(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress); + void device_update_ies(DeviceScene *dscene); + + /* Check whether light manager can use the object as a light-emissive. */ + bool object_usable_as_light(Object *object); + + struct IESSlot { + IESFile ies; + uint hash; + int users; + }; + + vector<IESSlot *> ies_slots; + thread_mutex ies_mutex; }; CCL_NAMESPACE_END -#endif /* __LIGHT_H__ */ +#endif /* __LIGHT_H__ */ diff --git a/intern/cycles/render/merge.cpp b/intern/cycles/render/merge.cpp index 289bb023d72..cac07e59fe3 100644 --- a/intern/cycles/render/merge.cpp +++ b/intern/cycles/render/merge.cpp @@ -32,453 +32,443 @@ CCL_NAMESPACE_BEGIN /* Merge Image Layer */ enum MergeChannelOp { - MERGE_CHANNEL_NOP, - MERGE_CHANNEL_COPY, - MERGE_CHANNEL_SUM, - MERGE_CHANNEL_AVERAGE + MERGE_CHANNEL_NOP, + MERGE_CHANNEL_COPY, + MERGE_CHANNEL_SUM, + MERGE_CHANNEL_AVERAGE }; struct MergeImagePass { - /* Full channel name. */ - string channel_name; - /* Channel format in the file. */ - TypeDesc format; - /* Type of operation to perform when merging. */ - MergeChannelOp op; - /* Offset of layer channels in input image. */ - int offset; - /* Offset of layer channels in merged image. */ - int merge_offset; + /* Full channel name. */ + string channel_name; + /* Channel format in the file. */ + TypeDesc format; + /* Type of operation to perform when merging. */ + MergeChannelOp op; + /* Offset of layer channels in input image. */ + int offset; + /* Offset of layer channels in merged image. */ + int merge_offset; }; struct MergeImageLayer { - /* Layer name. */ - string name; - /* Passes. */ - vector<MergeImagePass> passes; - /* Sample amount that was used for rendering this layer. */ - int samples; + /* Layer name. */ + string name; + /* Passes. */ + vector<MergeImagePass> passes; + /* Sample amount that was used for rendering this layer. */ + int samples; }; /* Merge Image */ struct MergeImage { - /* OIIO file handle. */ - unique_ptr<ImageInput> in; - /* Image file path. */ - string filepath; - /* Render layers. */ - vector<MergeImageLayer> layers; + /* OIIO file handle. */ + unique_ptr<ImageInput> in; + /* Image file path. */ + string filepath; + /* Render layers. */ + vector<MergeImageLayer> layers; }; /* Channel Parsing */ -static MergeChannelOp parse_channel_operation(const string& pass_name) +static MergeChannelOp parse_channel_operation(const string &pass_name) { - if(pass_name == "Depth" || - pass_name == "IndexMA" || - pass_name == "IndexOB" || - string_startswith(pass_name, "Crypto")) - { - return MERGE_CHANNEL_COPY; - } - else if(string_startswith(pass_name, "Debug BVH") || - string_startswith(pass_name, "Debug Ray") || - string_startswith(pass_name, "Debug Render Time")) - { - return MERGE_CHANNEL_SUM; - } - else { - return MERGE_CHANNEL_AVERAGE; - } + if (pass_name == "Depth" || pass_name == "IndexMA" || pass_name == "IndexOB" || + string_startswith(pass_name, "Crypto")) { + return MERGE_CHANNEL_COPY; + } + else if (string_startswith(pass_name, "Debug BVH") || + string_startswith(pass_name, "Debug Ray") || + string_startswith(pass_name, "Debug Render Time")) { + return MERGE_CHANNEL_SUM; + } + else { + return MERGE_CHANNEL_AVERAGE; + } } /* Splits in at its last dot, setting suffix to the part after the dot and * into the part before it. Returns whether a dot was found. */ static bool split_last_dot(string &in, string &suffix) { - size_t pos = in.rfind("."); - if(pos == string::npos) { - return false; - } - suffix = in.substr(pos+1); - in = in.substr(0, pos); - return true; + size_t pos = in.rfind("."); + if (pos == string::npos) { + return false; + } + suffix = in.substr(pos + 1); + in = in.substr(0, pos); + return true; } /* Separate channel names as generated by Blender. * Multiview format: RenderLayer.Pass.View.Channel * Otherwise: RenderLayer.Pass.Channel */ -static bool parse_channel_name(string name, - string &renderlayer, - string &pass, - string &channel, - bool multiview_channels) +static bool parse_channel_name( + string name, string &renderlayer, string &pass, string &channel, bool multiview_channels) { - if(!split_last_dot(name, channel)) { - return false; - } - string view; - if(multiview_channels && !split_last_dot(name, view)) { - return false; - } - if(!split_last_dot(name, pass)) { - return false; - } - renderlayer = name; - - if(multiview_channels) { - renderlayer += "." + view; - } - - return true; + if (!split_last_dot(name, channel)) { + return false; + } + string view; + if (multiview_channels && !split_last_dot(name, view)) { + return false; + } + if (!split_last_dot(name, pass)) { + return false; + } + renderlayer = name; + + if (multiview_channels) { + renderlayer += "." + view; + } + + return true; } static bool parse_channels(const ImageSpec &in_spec, - vector<MergeImageLayer>& layers, - string& error) + vector<MergeImageLayer> &layers, + string &error) { - const ParamValue *multiview = in_spec.find_attribute("multiView"); - const bool multiview_channels = (multiview && - multiview->type().basetype == TypeDesc::STRING && - multiview->type().arraylen >= 2); - - layers.clear(); - - /* Loop over all the channels in the file, parse their name and sort them - * by RenderLayer. - * Channels that can't be parsed are directly passed through to the output. */ - map<string, MergeImageLayer> file_layers; - for(int i = 0; i < in_spec.nchannels; i++) { - MergeImagePass pass; - pass.channel_name = in_spec.channelnames[i]; - pass.format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format; - pass.offset = i; - pass.merge_offset = i; - - string layername, passname, channelname; - if(parse_channel_name(pass.channel_name, layername, passname, channelname, multiview_channels)) { - /* Channer part of a render layer. */ - pass.op = parse_channel_operation(passname); - } - else { - /* Other channels are added in unnamed layer. */ - layername = ""; - pass.op = parse_channel_operation(pass.channel_name); - } - - file_layers[layername].passes.push_back(pass); - } - - /* Loop over all detected RenderLayers, check whether they contain a full set of input channels. - * Any channels that won't be processed internally are also passed through. */ - for(auto& i: file_layers) { - const string& name = i.first; - MergeImageLayer& layer = i.second; - - layer.name = name; - layer.samples = 0; - - /* Determine number of samples from metadata. */ - if(layer.name == "") { - layer.samples = 1; - } - else if(layer.samples < 1) { - string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", ""); - if(sample_string != "") { - if(!sscanf(sample_string.c_str(), "%d", &layer.samples)) { - error = "Failed to parse samples metadata: " + sample_string; - return false; - } - } - } - - if(layer.samples < 1) { - error = string_printf("No sample number specified in the file for layer %s or on the command line", name.c_str()); - return false; - } - - layers.push_back(layer); - } - - return true; + const ParamValue *multiview = in_spec.find_attribute("multiView"); + const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING && + multiview->type().arraylen >= 2); + + layers.clear(); + + /* Loop over all the channels in the file, parse their name and sort them + * by RenderLayer. + * Channels that can't be parsed are directly passed through to the output. */ + map<string, MergeImageLayer> file_layers; + for (int i = 0; i < in_spec.nchannels; i++) { + MergeImagePass pass; + pass.channel_name = in_spec.channelnames[i]; + pass.format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format; + pass.offset = i; + pass.merge_offset = i; + + string layername, passname, channelname; + if (parse_channel_name( + pass.channel_name, layername, passname, channelname, multiview_channels)) { + /* Channer part of a render layer. */ + pass.op = parse_channel_operation(passname); + } + else { + /* Other channels are added in unnamed layer. */ + layername = ""; + pass.op = parse_channel_operation(pass.channel_name); + } + + file_layers[layername].passes.push_back(pass); + } + + /* Loop over all detected RenderLayers, check whether they contain a full set of input channels. + * Any channels that won't be processed internally are also passed through. */ + for (auto &i : file_layers) { + const string &name = i.first; + MergeImageLayer &layer = i.second; + + layer.name = name; + layer.samples = 0; + + /* Determine number of samples from metadata. */ + if (layer.name == "") { + layer.samples = 1; + } + else if (layer.samples < 1) { + string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", ""); + if (sample_string != "") { + if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) { + error = "Failed to parse samples metadata: " + sample_string; + return false; + } + } + } + + if (layer.samples < 1) { + error = string_printf( + "No sample number specified in the file for layer %s or on the command line", + name.c_str()); + return false; + } + + layers.push_back(layer); + } + + return true; } -static bool open_images(const vector<string>& filepaths, - vector<MergeImage>& images, - string& error) +static bool open_images(const vector<string> &filepaths, vector<MergeImage> &images, string &error) { - for(const string& filepath: filepaths) { - unique_ptr<ImageInput> in(ImageInput::open(filepath)); - if(!in) { - error = "Couldn't open file: " + filepath; - return false; - } - - MergeImage image; - image.in = std::move(in); - image.filepath = filepath; - if(!parse_channels(image.in->spec(), image.layers, error)) { - return false; - } - - if(image.layers.size() == 0) { - error = "Could not find a render layer for merging"; - return false; - } - - if(image.in->spec().deep) { - error = "Merging deep images not supported."; - return false; - } - - if(images.size() > 0) { - const ImageSpec& base_spec = images[0].in->spec(); - const ImageSpec& spec = image.in->spec(); - - if(base_spec.width != spec.width || - base_spec.height != spec.height || - base_spec.depth != spec.depth || - base_spec.format != spec.format || - base_spec.deep != spec.deep) - { - error = "Images do not have matching size and data layout."; - return false; - } - } - - images.push_back(std::move(image)); - } - - return true; + for (const string &filepath : filepaths) { + unique_ptr<ImageInput> in(ImageInput::open(filepath)); + if (!in) { + error = "Couldn't open file: " + filepath; + return false; + } + + MergeImage image; + image.in = std::move(in); + image.filepath = filepath; + if (!parse_channels(image.in->spec(), image.layers, error)) { + return false; + } + + if (image.layers.size() == 0) { + error = "Could not find a render layer for merging"; + return false; + } + + if (image.in->spec().deep) { + error = "Merging deep images not supported."; + return false; + } + + if (images.size() > 0) { + const ImageSpec &base_spec = images[0].in->spec(); + const ImageSpec &spec = image.in->spec(); + + if (base_spec.width != spec.width || base_spec.height != spec.height || + base_spec.depth != spec.depth || base_spec.format != spec.format || + base_spec.deep != spec.deep) { + error = "Images do not have matching size and data layout."; + return false; + } + } + + images.push_back(std::move(image)); + } + + return true; } -static void merge_render_time(ImageSpec& spec, - const vector<MergeImage>& images, - const string& name, +static void merge_render_time(ImageSpec &spec, + const vector<MergeImage> &images, + const string &name, const bool average) { - double time = 0.0; + double time = 0.0; - for(const MergeImage& image: images) { - string time_str = image.in->spec().get_string_attribute(name, ""); - time += time_human_readable_to_seconds(time_str); - } + for (const MergeImage &image : images) { + string time_str = image.in->spec().get_string_attribute(name, ""); + time += time_human_readable_to_seconds(time_str); + } - if(average) { - time /= images.size(); - } + if (average) { + time /= images.size(); + } - spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time)); + spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time)); } -static void merge_layer_render_time(ImageSpec& spec, - const vector<MergeImage>& images, - const string& layer_name, - const string& time_name, +static void merge_layer_render_time(ImageSpec &spec, + const vector<MergeImage> &images, + const string &layer_name, + const string &time_name, const bool average) { - string name = "cycles." + layer_name + "." + time_name; - double time = 0.0; + string name = "cycles." + layer_name + "." + time_name; + double time = 0.0; - for(const MergeImage& image: images) { - string time_str = image.in->spec().get_string_attribute(name, ""); - time += time_human_readable_to_seconds(time_str); - } + for (const MergeImage &image : images) { + string time_str = image.in->spec().get_string_attribute(name, ""); + time += time_human_readable_to_seconds(time_str); + } - if(average) { - time /= images.size(); - } + if (average) { + time /= images.size(); + } - spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time)); + spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time)); } -static void merge_channels_metadata(vector<MergeImage>& images, - ImageSpec& out_spec, - vector<int>& channel_total_samples) +static void merge_channels_metadata(vector<MergeImage> &images, + ImageSpec &out_spec, + vector<int> &channel_total_samples) { - /* Based on first image. */ - out_spec = images[0].in->spec(); - - /* Merge channels and compute offsets. */ - out_spec.nchannels = 0; - out_spec.channelformats.clear(); - out_spec.channelnames.clear(); - - for(MergeImage& image: images) { - for(MergeImageLayer& layer: image.layers) { - for(MergeImagePass& pass: layer.passes) { - /* Test if matching channel already exists in merged image. */ - bool found = false; - - for(size_t i = 0; i < out_spec.nchannels; i++) { - if(pass.channel_name == out_spec.channelnames[i]) { - pass.merge_offset = i; - channel_total_samples[i] += layer.samples; - /* First image wins for channels that can't be averaged or summed. */ - if (pass.op == MERGE_CHANNEL_COPY) { - pass.op = MERGE_CHANNEL_NOP; - } - found = true; - break; - } - } - - if(!found) { - /* Add new channel. */ - pass.merge_offset = out_spec.nchannels; - channel_total_samples.push_back(layer.samples); - - out_spec.channelnames.push_back(pass.channel_name); - out_spec.channelformats.push_back(pass.format); - out_spec.nchannels++; - } - } - } - } - - /* Merge metadata. */ - merge_render_time(out_spec, images, "RenderTime", false); - - map<string, int> layer_num_samples; - for(MergeImage& image: images) { - for(MergeImageLayer& layer: image.layers) { - if(layer.name != "") { - layer_num_samples[layer.name] += layer.samples; - } - } - } - - for(const auto& i: layer_num_samples) { - string name = "cycles." + i.first + ".samples"; - out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second)); - - merge_layer_render_time(out_spec, images, i.first, "total_time", false); - merge_layer_render_time(out_spec, images, i.first, "render_time", false); - merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true); - } + /* Based on first image. */ + out_spec = images[0].in->spec(); + + /* Merge channels and compute offsets. */ + out_spec.nchannels = 0; + out_spec.channelformats.clear(); + out_spec.channelnames.clear(); + + for (MergeImage &image : images) { + for (MergeImageLayer &layer : image.layers) { + for (MergeImagePass &pass : layer.passes) { + /* Test if matching channel already exists in merged image. */ + bool found = false; + + for (size_t i = 0; i < out_spec.nchannels; i++) { + if (pass.channel_name == out_spec.channelnames[i]) { + pass.merge_offset = i; + channel_total_samples[i] += layer.samples; + /* First image wins for channels that can't be averaged or summed. */ + if (pass.op == MERGE_CHANNEL_COPY) { + pass.op = MERGE_CHANNEL_NOP; + } + found = true; + break; + } + } + + if (!found) { + /* Add new channel. */ + pass.merge_offset = out_spec.nchannels; + channel_total_samples.push_back(layer.samples); + + out_spec.channelnames.push_back(pass.channel_name); + out_spec.channelformats.push_back(pass.format); + out_spec.nchannels++; + } + } + } + } + + /* Merge metadata. */ + merge_render_time(out_spec, images, "RenderTime", false); + + map<string, int> layer_num_samples; + for (MergeImage &image : images) { + for (MergeImageLayer &layer : image.layers) { + if (layer.name != "") { + layer_num_samples[layer.name] += layer.samples; + } + } + } + + for (const auto &i : layer_num_samples) { + string name = "cycles." + i.first + ".samples"; + out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second)); + + merge_layer_render_time(out_spec, images, i.first, "total_time", false); + merge_layer_render_time(out_spec, images, i.first, "render_time", false); + merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true); + } } -static void alloc_pixels(const ImageSpec& spec, array<float>& pixels) +static void alloc_pixels(const ImageSpec &spec, array<float> &pixels) { - const size_t width = spec.width; - const size_t height = spec.height; - const size_t num_channels = spec.nchannels; + const size_t width = spec.width; + const size_t height = spec.height; + const size_t num_channels = spec.nchannels; - const size_t num_pixels = (size_t)width * (size_t)height; - pixels.resize(num_pixels * num_channels); + const size_t num_pixels = (size_t)width * (size_t)height; + pixels.resize(num_pixels * num_channels); } -static bool merge_pixels(const vector<MergeImage>& images, - const ImageSpec& out_spec, - const vector<int>& channel_total_samples, - array<float>& out_pixels, - string& error) +static bool merge_pixels(const vector<MergeImage> &images, + const ImageSpec &out_spec, + const vector<int> &channel_total_samples, + array<float> &out_pixels, + string &error) { - alloc_pixels(out_spec, out_pixels); - memset(out_pixels.data(), 0, out_pixels.size() * sizeof(float)); - - for(const MergeImage& image: images) { - /* Read all channels into buffer. Reading all channels at once is - * faster than individually due to interleaved EXR channel storage. */ - array<float> pixels; - alloc_pixels(image.in->spec(), pixels); - - if(!image.in->read_image(TypeDesc::FLOAT, pixels.data())) { - error = "Failed to read image: " + image.filepath; - return false; - } - - for(size_t li = 0; li < image.layers.size(); li++) { - const MergeImageLayer& layer = image.layers[li]; - - const size_t stride = image.in->spec().nchannels; - const size_t out_stride = out_spec.nchannels; - const size_t num_pixels = pixels.size(); - - for(const MergeImagePass& pass: layer.passes) { - size_t offset = pass.offset; - size_t out_offset = pass.merge_offset; - - switch(pass.op) { - case MERGE_CHANNEL_NOP: - break; - case MERGE_CHANNEL_COPY: - for(; offset < num_pixels; offset += stride, out_offset += out_stride) { - out_pixels[out_offset] = pixels[offset]; - } - break; - case MERGE_CHANNEL_SUM: - for(; offset < num_pixels; offset += stride, out_offset += out_stride) { - out_pixels[out_offset] += pixels[offset]; - } - break; - case MERGE_CHANNEL_AVERAGE: - /* Weights based on sample metadata. Per channel since not - * all files are guaranteed to have the same channels. */ - const int total_samples = channel_total_samples[out_offset]; - const float t = (float)layer.samples / (float)total_samples; - - for(; offset < num_pixels; offset += stride, out_offset += out_stride) { - out_pixels[out_offset] += t * pixels[offset]; - } - break; - } - } - } - } - - return true; + alloc_pixels(out_spec, out_pixels); + memset(out_pixels.data(), 0, out_pixels.size() * sizeof(float)); + + for (const MergeImage &image : images) { + /* Read all channels into buffer. Reading all channels at once is + * faster than individually due to interleaved EXR channel storage. */ + array<float> pixels; + alloc_pixels(image.in->spec(), pixels); + + if (!image.in->read_image(TypeDesc::FLOAT, pixels.data())) { + error = "Failed to read image: " + image.filepath; + return false; + } + + for (size_t li = 0; li < image.layers.size(); li++) { + const MergeImageLayer &layer = image.layers[li]; + + const size_t stride = image.in->spec().nchannels; + const size_t out_stride = out_spec.nchannels; + const size_t num_pixels = pixels.size(); + + for (const MergeImagePass &pass : layer.passes) { + size_t offset = pass.offset; + size_t out_offset = pass.merge_offset; + + switch (pass.op) { + case MERGE_CHANNEL_NOP: + break; + case MERGE_CHANNEL_COPY: + for (; offset < num_pixels; offset += stride, out_offset += out_stride) { + out_pixels[out_offset] = pixels[offset]; + } + break; + case MERGE_CHANNEL_SUM: + for (; offset < num_pixels; offset += stride, out_offset += out_stride) { + out_pixels[out_offset] += pixels[offset]; + } + break; + case MERGE_CHANNEL_AVERAGE: + /* Weights based on sample metadata. Per channel since not + * all files are guaranteed to have the same channels. */ + const int total_samples = channel_total_samples[out_offset]; + const float t = (float)layer.samples / (float)total_samples; + + for (; offset < num_pixels; offset += stride, out_offset += out_stride) { + out_pixels[out_offset] += t * pixels[offset]; + } + break; + } + } + } + } + + return true; } -static bool save_output(const string& filepath, - const ImageSpec& spec, - const array<float>& pixels, - string& error) +static bool save_output(const string &filepath, + const ImageSpec &spec, + const array<float> &pixels, + string &error) { - /* Write to temporary file path, so we merge images in place and don't - * risk destroying files when something goes wrong in file saving. */ - string extension = OIIO::Filesystem::extension(filepath); - string unique_name = ".merge-tmp-" + OIIO::Filesystem::unique_path(); - string tmp_filepath = filepath + unique_name + extension; - unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath)); - - if(!out) { - error = "Failed to open temporary file " + tmp_filepath + " for writing"; - return false; - } - - /* Open temporary file and write image buffers. */ - if(!out->open(tmp_filepath, spec)) { - error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror(); - return false; - } - - bool ok = true; - if(!out->write_image(TypeDesc::FLOAT, pixels.data())) { - error = "Failed to write to file " + tmp_filepath + ": " + out->geterror(); - ok = false; - } - - if(!out->close()) { - error = "Failed to save to file " + tmp_filepath + ": " + out->geterror(); - ok = false; - } - - out.reset(); - - /* Copy temporary file to outputput filepath. */ - string rename_error; - if(ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) { - error = "Failed to move merged image to " + filepath + ": " + rename_error; - ok = false; - } - - if(!ok) { - OIIO::Filesystem::remove(tmp_filepath); - } - - return ok; + /* Write to temporary file path, so we merge images in place and don't + * risk destroying files when something goes wrong in file saving. */ + string extension = OIIO::Filesystem::extension(filepath); + string unique_name = ".merge-tmp-" + OIIO::Filesystem::unique_path(); + string tmp_filepath = filepath + unique_name + extension; + unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath)); + + if (!out) { + error = "Failed to open temporary file " + tmp_filepath + " for writing"; + return false; + } + + /* Open temporary file and write image buffers. */ + if (!out->open(tmp_filepath, spec)) { + error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror(); + return false; + } + + bool ok = true; + if (!out->write_image(TypeDesc::FLOAT, pixels.data())) { + error = "Failed to write to file " + tmp_filepath + ": " + out->geterror(); + ok = false; + } + + if (!out->close()) { + error = "Failed to save to file " + tmp_filepath + ": " + out->geterror(); + ok = false; + } + + out.reset(); + + /* Copy temporary file to outputput filepath. */ + string rename_error; + if (ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) { + error = "Failed to move merged image to " + filepath + ": " + rename_error; + ok = false; + } + + if (!ok) { + OIIO::Filesystem::remove(tmp_filepath); + } + + return ok; } /* Image Merger */ @@ -489,38 +479,38 @@ ImageMerger::ImageMerger() bool ImageMerger::run() { - if(input.empty()) { - error = "No input file paths specified."; - return false; - } - if(output.empty()) { - error = "No output file path specified."; - return false; - } - - /* Open images and verify they have matching layout. */ - vector<MergeImage> images; - if(!open_images(input, images, error)) { - return false; - } - - /* Merge metadata and setup channels and offsets. */ - ImageSpec out_spec; - vector<int> channel_total_samples; - merge_channels_metadata(images, out_spec, channel_total_samples); - - /* Merge pixels. */ - array<float> out_pixels; - if(!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) { - return false; - } - - /* We don't need input anymore at this point, and will possibly - * overwrite the same file. */ - images.clear(); - - /* Save output file. */ - return save_output(output, out_spec, out_pixels, error); + if (input.empty()) { + error = "No input file paths specified."; + return false; + } + if (output.empty()) { + error = "No output file path specified."; + return false; + } + + /* Open images and verify they have matching layout. */ + vector<MergeImage> images; + if (!open_images(input, images, error)) { + return false; + } + + /* Merge metadata and setup channels and offsets. */ + ImageSpec out_spec; + vector<int> channel_total_samples; + merge_channels_metadata(images, out_spec, channel_total_samples); + + /* Merge pixels. */ + array<float> out_pixels; + if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) { + return false; + } + + /* We don't need input anymore at this point, and will possibly + * overwrite the same file. */ + images.clear(); + + /* Save output file. */ + return save_output(output, out_spec, out_pixels, error); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/merge.h b/intern/cycles/render/merge.h index 48900a13c27..87e5d2d4723 100644 --- a/intern/cycles/render/merge.h +++ b/intern/cycles/render/merge.h @@ -25,17 +25,17 @@ CCL_NAMESPACE_BEGIN /* Merge OpenEXR multilayer renders. */ class ImageMerger { -public: - ImageMerger(); - bool run(); + public: + ImageMerger(); + bool run(); - /* Error message after running, in case of failure. */ - string error; + /* Error message after running, in case of failure. */ + string error; - /* List of image filepaths to merge. */ - vector<string> input; - /* Output filepath. */ - string output; + /* List of image filepaths to merge. */ + vector<string> input; + /* Output filepath. */ + string output; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index eadbe3eda89..54dacf5d1f4 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -47,11 +47,11 @@ CCL_NAMESPACE_BEGIN /* Triangle */ -void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const +void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox &bounds) const { - bounds.grow(verts[v[0]]); - bounds.grow(verts[v[1]]); - bounds.grow(verts[v[2]]); + bounds.grow(verts[v[0]]); + bounds.grow(verts[v[1]]); + bounds.grow(verts[v[2]]); } void Mesh::Triangle::motion_verts(const float3 *verts, @@ -61,29 +61,19 @@ void Mesh::Triangle::motion_verts(const float3 *verts, float time, float3 r_verts[3]) const { - /* Figure out which steps we need to fetch and their interpolation factor. */ - const size_t max_step = num_steps - 1; - const size_t step = min((int)(time * max_step), max_step - 1); - const float t = time*max_step - step; - /* Fetch vertex coordinates. */ - float3 curr_verts[3]; - float3 next_verts[3]; - verts_for_step(verts, - vert_steps, - num_verts, - num_steps, - step, - curr_verts); - verts_for_step(verts, - vert_steps, - num_verts, - num_steps, - step + 1, - next_verts); - /* Interpolate between steps. */ - r_verts[0] = (1.0f - t)*curr_verts[0] + t*next_verts[0]; - r_verts[1] = (1.0f - t)*curr_verts[1] + t*next_verts[1]; - r_verts[2] = (1.0f - t)*curr_verts[2] + t*next_verts[2]; + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float3 curr_verts[3]; + float3 next_verts[3]; + verts_for_step(verts, vert_steps, num_verts, num_steps, step, curr_verts); + verts_for_step(verts, vert_steps, num_verts, num_steps, step + 1, next_verts); + /* Interpolate between steps. */ + r_verts[0] = (1.0f - t) * curr_verts[0] + t * next_verts[0]; + r_verts[1] = (1.0f - t) * curr_verts[1] + t * next_verts[1]; + r_verts[2] = (1.0f - t) * curr_verts[2] + t * next_verts[2]; } void Mesh::Triangle::verts_for_step(const float3 *verts, @@ -93,120 +83,121 @@ void Mesh::Triangle::verts_for_step(const float3 *verts, size_t step, float3 r_verts[3]) const { - const size_t center_step = ((num_steps - 1) / 2); - if(step == center_step) { - /* Center step: regular vertex location. */ - r_verts[0] = verts[v[0]]; - r_verts[1] = verts[v[1]]; - r_verts[2] = verts[v[2]]; - } - else { - /* Center step not stored in the attribute array array. */ - if(step > center_step) { - step--; - } - size_t offset = step * num_verts; - r_verts[0] = vert_steps[offset + v[0]]; - r_verts[1] = vert_steps[offset + v[1]]; - r_verts[2] = vert_steps[offset + v[2]]; - } + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular vertex location. */ + r_verts[0] = verts[v[0]]; + r_verts[1] = verts[v[1]]; + r_verts[2] = verts[v[2]]; + } + else { + /* Center step not stored in the attribute array array. */ + if (step > center_step) { + step--; + } + size_t offset = step * num_verts; + r_verts[0] = vert_steps[offset + v[0]]; + r_verts[1] = vert_steps[offset + v[1]]; + r_verts[2] = vert_steps[offset + v[2]]; + } } float3 Mesh::Triangle::compute_normal(const float3 *verts) const { - const float3& v0 = verts[v[0]]; - const float3& v1 = verts[v[1]]; - const float3& v2 = verts[v[2]]; - const float3 norm = cross(v1 - v0, v2 - v0); - const float normlen = len(norm); - if(normlen == 0.0f) { - return make_float3(1.0f, 0.0f, 0.0f); - } - return norm / normlen; + const float3 &v0 = verts[v[0]]; + const float3 &v1 = verts[v[1]]; + const float3 &v2 = verts[v[2]]; + const float3 norm = cross(v1 - v0, v2 - v0); + const float normlen = len(norm); + if (normlen == 0.0f) { + return make_float3(1.0f, 0.0f, 0.0f); + } + return norm / normlen; } bool Mesh::Triangle::valid(const float3 *verts) const { - return isfinite3_safe(verts[v[0]]) && - isfinite3_safe(verts[v[1]]) && - isfinite3_safe(verts[v[2]]); + return isfinite3_safe(verts[v[0]]) && isfinite3_safe(verts[v[1]]) && isfinite3_safe(verts[v[2]]); } /* Curve */ -void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const +void Mesh::Curve::bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + BoundBox &bounds) const { - float3 P[4]; + float3 P[4]; - P[0] = curve_keys[max(first_key + k - 1,first_key)]; - P[1] = curve_keys[first_key + k]; - P[2] = curve_keys[first_key + k + 1]; - P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + P[0] = curve_keys[max(first_key + k - 1, first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; - float3 lower; - float3 upper; + float3 lower; + float3 upper; - curvebounds(&lower.x, &upper.x, P, 0); - curvebounds(&lower.y, &upper.y, P, 1); - curvebounds(&lower.z, &upper.z, P, 2); + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); - float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); - bounds.grow(lower, mr); - bounds.grow(upper, mr); + bounds.grow(lower, mr); + bounds.grow(upper, mr); } void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, - const Transform& aligned_space, - BoundBox& bounds) const + const Transform &aligned_space, + BoundBox &bounds) const { - float3 P[4]; + float3 P[4]; - P[0] = curve_keys[max(first_key + k - 1,first_key)]; - P[1] = curve_keys[first_key + k]; - P[2] = curve_keys[first_key + k + 1]; - P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + P[0] = curve_keys[max(first_key + k - 1, first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; - P[0] = transform_point(&aligned_space, P[0]); - P[1] = transform_point(&aligned_space, P[1]); - P[2] = transform_point(&aligned_space, P[2]); - P[3] = transform_point(&aligned_space, P[3]); + P[0] = transform_point(&aligned_space, P[0]); + P[1] = transform_point(&aligned_space, P[1]); + P[2] = transform_point(&aligned_space, P[2]); + P[3] = transform_point(&aligned_space, P[3]); - float3 lower; - float3 upper; + float3 lower; + float3 upper; - curvebounds(&lower.x, &upper.x, P, 0); - curvebounds(&lower.y, &upper.y, P, 1); - curvebounds(&lower.z, &upper.z, P, 2); + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); - float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); - bounds.grow(lower, mr); - bounds.grow(upper, mr); + bounds.grow(lower, mr); + bounds.grow(upper, mr); } -void Mesh::Curve::bounds_grow(float4 keys[4], BoundBox& bounds) const +void Mesh::Curve::bounds_grow(float4 keys[4], BoundBox &bounds) const { - float3 P[4] = { - float4_to_float3(keys[0]), - float4_to_float3(keys[1]), - float4_to_float3(keys[2]), - float4_to_float3(keys[3]), - }; + float3 P[4] = { + float4_to_float3(keys[0]), + float4_to_float3(keys[1]), + float4_to_float3(keys[2]), + float4_to_float3(keys[3]), + }; - float3 lower; - float3 upper; + float3 lower; + float3 upper; - curvebounds(&lower.x, &upper.x, P, 0); - curvebounds(&lower.y, &upper.y, P, 1); - curvebounds(&lower.z, &upper.z, P, 2); + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); - float mr = max(keys[1].w, keys[2].w); + float mr = max(keys[1].w, keys[2].w); - bounds.grow(lower, mr); - bounds.grow(upper, mr); + bounds.grow(lower, mr); + bounds.grow(upper, mr); } void Mesh::Curve::motion_keys(const float3 *curve_keys, @@ -215,35 +206,24 @@ void Mesh::Curve::motion_keys(const float3 *curve_keys, size_t num_curve_keys, size_t num_steps, float time, - size_t k0, size_t k1, + size_t k0, + size_t k1, float4 r_keys[2]) const { - /* Figure out which steps we need to fetch and their interpolation factor. */ - const size_t max_step = num_steps - 1; - const size_t step = min((int)(time * max_step), max_step - 1); - const float t = time*max_step - step; - /* Fetch vertex coordinates. */ - float4 curr_keys[2]; - float4 next_keys[2]; - keys_for_step(curve_keys, - curve_radius, - key_steps, - num_curve_keys, - num_steps, - step, - k0, k1, - curr_keys); - keys_for_step(curve_keys, - curve_radius, - key_steps, - num_curve_keys, - num_steps, - step + 1, - k0, k1, - next_keys); - /* Interpolate between steps. */ - r_keys[0] = (1.0f - t)*curr_keys[0] + t*next_keys[0]; - r_keys[1] = (1.0f - t)*curr_keys[1] + t*next_keys[1]; + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[2]; + float4 next_keys[2]; + keys_for_step( + curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step, k0, k1, curr_keys); + keys_for_step( + curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step + 1, k0, k1, next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; + r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; } void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, @@ -252,38 +232,46 @@ void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, size_t num_curve_keys, size_t num_steps, float time, - size_t k0, size_t k1, - size_t k2, size_t k3, + size_t k0, + size_t k1, + size_t k2, + size_t k3, float4 r_keys[4]) const { - /* Figure out which steps we need to fetch and their interpolation factor. */ - const size_t max_step = num_steps - 1; - const size_t step = min((int)(time * max_step), max_step - 1); - const float t = time*max_step - step; - /* Fetch vertex coordinates. */ - float4 curr_keys[4]; - float4 next_keys[4]; - cardinal_keys_for_step(curve_keys, - curve_radius, - key_steps, - num_curve_keys, - num_steps, - step, - k0, k1, k2, k3, - curr_keys); - cardinal_keys_for_step(curve_keys, - curve_radius, - key_steps, - num_curve_keys, - num_steps, - step + 1, - k0, k1, k2, k3, - next_keys); - /* Interpolate between steps. */ - r_keys[0] = (1.0f - t)*curr_keys[0] + t*next_keys[0]; - r_keys[1] = (1.0f - t)*curr_keys[1] + t*next_keys[1]; - r_keys[2] = (1.0f - t)*curr_keys[2] + t*next_keys[2]; - r_keys[3] = (1.0f - t)*curr_keys[3] + t*next_keys[3]; + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[4]; + float4 next_keys[4]; + cardinal_keys_for_step(curve_keys, + curve_radius, + key_steps, + num_curve_keys, + num_steps, + step, + k0, + k1, + k2, + k3, + curr_keys); + cardinal_keys_for_step(curve_keys, + curve_radius, + key_steps, + num_curve_keys, + num_steps, + step + 1, + k0, + k1, + k2, + k3, + next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; + r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; + r_keys[2] = (1.0f - t) * curr_keys[2] + t * next_keys[2]; + r_keys[3] = (1.0f - t) * curr_keys[3] + t * next_keys[3]; } void Mesh::Curve::keys_for_step(const float3 *curve_keys, @@ -292,41 +280,42 @@ void Mesh::Curve::keys_for_step(const float3 *curve_keys, size_t num_curve_keys, size_t num_steps, size_t step, - size_t k0, size_t k1, + size_t k0, + size_t k1, float4 r_keys[2]) const { - k0 = max(k0, 0); - k1 = min(k1, num_keys - 1); - const size_t center_step = ((num_steps - 1) / 2); - if(step == center_step) { - /* Center step: regular key location. */ - /* TODO(sergey): Consider adding make_float4(float3, float) - * function. - */ - r_keys[0] = make_float4(curve_keys[first_key + k0].x, - curve_keys[first_key + k0].y, - curve_keys[first_key + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(curve_keys[first_key + k1].x, - curve_keys[first_key + k1].y, - curve_keys[first_key + k1].z, - curve_radius[first_key + k1]); - } - else { - /* Center step is not stored in this array. */ - if(step > center_step) { - step--; - } - const size_t offset = first_key + step * num_curve_keys; - r_keys[0] = make_float4(key_steps[offset + k0].x, - key_steps[offset + k0].y, - key_steps[offset + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(key_steps[offset + k1].x, - key_steps[offset + k1].y, - key_steps[offset + k1].z, - curve_radius[first_key + k1]); - } + k0 = max(k0, 0); + k1 = min(k1, num_keys - 1); + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular key location. */ + /* TODO(sergey): Consider adding make_float4(float3, float) + * function. + */ + r_keys[0] = make_float4(curve_keys[first_key + k0].x, + curve_keys[first_key + k0].y, + curve_keys[first_key + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(curve_keys[first_key + k1].x, + curve_keys[first_key + k1].y, + curve_keys[first_key + k1].z, + curve_radius[first_key + k1]); + } + else { + /* Center step is not stored in this array. */ + if (step > center_step) { + step--; + } + const size_t offset = first_key + step * num_curve_keys; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + curve_radius[first_key + k1]); + } } void Mesh::Curve::cardinal_keys_for_step(const float3 *curve_keys, @@ -335,2033 +324,2044 @@ void Mesh::Curve::cardinal_keys_for_step(const float3 *curve_keys, size_t num_curve_keys, size_t num_steps, size_t step, - size_t k0, size_t k1, - size_t k2, size_t k3, + size_t k0, + size_t k1, + size_t k2, + size_t k3, float4 r_keys[4]) const { - k0 = max(k0, 0); - k3 = min(k3, num_keys - 1); - const size_t center_step = ((num_steps - 1) / 2); - if(step == center_step) { - /* Center step: regular key location. */ - r_keys[0] = make_float4(curve_keys[first_key + k0].x, - curve_keys[first_key + k0].y, - curve_keys[first_key + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(curve_keys[first_key + k1].x, - curve_keys[first_key + k1].y, - curve_keys[first_key + k1].z, - curve_radius[first_key + k1]); - r_keys[2] = make_float4(curve_keys[first_key + k2].x, - curve_keys[first_key + k2].y, - curve_keys[first_key + k2].z, - curve_radius[first_key + k2]); - r_keys[3] = make_float4(curve_keys[first_key + k3].x, - curve_keys[first_key + k3].y, - curve_keys[first_key + k3].z, - curve_radius[first_key + k3]); - } - else { - /* Center step is not stored in this array. */ - if(step > center_step) { - step--; - } - const size_t offset = first_key + step * num_curve_keys; - r_keys[0] = make_float4(key_steps[offset + k0].x, - key_steps[offset + k0].y, - key_steps[offset + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(key_steps[offset + k1].x, - key_steps[offset + k1].y, - key_steps[offset + k1].z, - curve_radius[first_key + k1]); - r_keys[2] = make_float4(key_steps[offset + k2].x, - key_steps[offset + k2].y, - key_steps[offset + k2].z, - curve_radius[first_key + k2]); - r_keys[3] = make_float4(key_steps[offset + k3].x, - key_steps[offset + k3].y, - key_steps[offset + k3].z, - curve_radius[first_key + k3]); - } + k0 = max(k0, 0); + k3 = min(k3, num_keys - 1); + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular key location. */ + r_keys[0] = make_float4(curve_keys[first_key + k0].x, + curve_keys[first_key + k0].y, + curve_keys[first_key + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(curve_keys[first_key + k1].x, + curve_keys[first_key + k1].y, + curve_keys[first_key + k1].z, + curve_radius[first_key + k1]); + r_keys[2] = make_float4(curve_keys[first_key + k2].x, + curve_keys[first_key + k2].y, + curve_keys[first_key + k2].z, + curve_radius[first_key + k2]); + r_keys[3] = make_float4(curve_keys[first_key + k3].x, + curve_keys[first_key + k3].y, + curve_keys[first_key + k3].z, + curve_radius[first_key + k3]); + } + else { + /* Center step is not stored in this array. */ + if (step > center_step) { + step--; + } + const size_t offset = first_key + step * num_curve_keys; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + curve_radius[first_key + k1]); + r_keys[2] = make_float4(key_steps[offset + k2].x, + key_steps[offset + k2].y, + key_steps[offset + k2].z, + curve_radius[first_key + k2]); + r_keys[3] = make_float4(key_steps[offset + k3].x, + key_steps[offset + k3].y, + key_steps[offset + k3].z, + curve_radius[first_key + k3]); + } } /* SubdFace */ float3 Mesh::SubdFace::normal(const Mesh *mesh) const { - float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner+0]]; - float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner+1]]; - float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner+2]]; + float3 v0 = mesh->verts[mesh->subd_face_corners[start_corner + 0]]; + float3 v1 = mesh->verts[mesh->subd_face_corners[start_corner + 1]]; + float3 v2 = mesh->verts[mesh->subd_face_corners[start_corner + 2]]; - return safe_normalize(cross(v1 - v0, v2 - v0)); + return safe_normalize(cross(v1 - v0, v2 - v0)); } /* Mesh */ NODE_DEFINE(Mesh) { - NodeType* type = NodeType::add("mesh", create); + NodeType *type = NodeType::add("mesh", create); - SOCKET_UINT(motion_steps, "Motion Steps", 3); - SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); + SOCKET_UINT(motion_steps, "Motion Steps", 3); + SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); - SOCKET_INT_ARRAY(triangles, "Triangles", array<int>()); - SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>()); - SOCKET_INT_ARRAY(shader, "Shader", array<int>()); - SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>()); + SOCKET_INT_ARRAY(triangles, "Triangles", array<int>()); + SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>()); + SOCKET_INT_ARRAY(shader, "Shader", array<int>()); + SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>()); - SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>()); - SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>()); - SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>()); - SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>()); + SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>()); + SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>()); + SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>()); + SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>()); - return type; + return type; } -Mesh::Mesh() -: Node(node_type) +Mesh::Mesh() : Node(node_type) { - need_update = true; - need_update_rebuild = false; - transform_applied = false; - transform_negative_scaled = false; - transform_normal = transform_identity(); - bounds = BoundBox::empty; + need_update = true; + need_update_rebuild = false; + transform_applied = false; + transform_negative_scaled = false; + transform_normal = transform_identity(); + bounds = BoundBox::empty; - bvh = NULL; + bvh = NULL; - tri_offset = 0; - vert_offset = 0; + tri_offset = 0; + vert_offset = 0; - curve_offset = 0; - curvekey_offset = 0; + curve_offset = 0; + curvekey_offset = 0; - patch_offset = 0; - face_offset = 0; - corner_offset = 0; + patch_offset = 0; + face_offset = 0; + corner_offset = 0; - attr_map_offset = 0; + attr_map_offset = 0; - num_subd_verts = 0; + num_subd_verts = 0; - attributes.triangle_mesh = this; - curve_attributes.curve_mesh = this; - subd_attributes.subd_mesh = this; + attributes.triangle_mesh = this; + curve_attributes.curve_mesh = this; + subd_attributes.subd_mesh = this; - geometry_flags = GEOMETRY_NONE; + geometry_flags = GEOMETRY_NONE; - volume_isovalue = 0.001f; - has_volume = false; - has_surface_bssrdf = false; + volume_isovalue = 0.001f; + has_volume = false; + has_surface_bssrdf = false; - num_ngons = 0; + num_ngons = 0; - subdivision_type = SUBDIVISION_NONE; - subd_params = NULL; + subdivision_type = SUBDIVISION_NONE; + subd_params = NULL; - patch_table = NULL; + patch_table = NULL; } Mesh::~Mesh() { - delete bvh; - delete patch_table; - delete subd_params; + delete bvh; + delete patch_table; + delete subd_params; } void Mesh::resize_mesh(int numverts, int numtris) { - verts.resize(numverts); - triangles.resize(numtris * 3); - shader.resize(numtris); - smooth.resize(numtris); + verts.resize(numverts); + triangles.resize(numtris * 3); + shader.resize(numtris); + smooth.resize(numtris); - if(subd_faces.size()) { - triangle_patch.resize(numtris); - vert_patch_uv.resize(numverts); - } + if (subd_faces.size()) { + triangle_patch.resize(numtris); + vert_patch_uv.resize(numverts); + } - attributes.resize(); + attributes.resize(); } void Mesh::reserve_mesh(int numverts, int numtris) { - /* reserve space to add verts and triangles later */ - verts.reserve(numverts); - triangles.reserve(numtris * 3); - shader.reserve(numtris); - smooth.reserve(numtris); + /* reserve space to add verts and triangles later */ + verts.reserve(numverts); + triangles.reserve(numtris * 3); + shader.reserve(numtris); + smooth.reserve(numtris); - if(subd_faces.size()) { - triangle_patch.reserve(numtris); - vert_patch_uv.reserve(numverts); - } + if (subd_faces.size()) { + triangle_patch.reserve(numtris); + vert_patch_uv.reserve(numverts); + } - attributes.resize(true); + attributes.resize(true); } void Mesh::resize_curves(int numcurves, int numkeys) { - curve_keys.resize(numkeys); - curve_radius.resize(numkeys); - curve_first_key.resize(numcurves); - curve_shader.resize(numcurves); + curve_keys.resize(numkeys); + curve_radius.resize(numkeys); + curve_first_key.resize(numcurves); + curve_shader.resize(numcurves); - curve_attributes.resize(); + curve_attributes.resize(); } void Mesh::reserve_curves(int numcurves, int numkeys) { - curve_keys.reserve(numkeys); - curve_radius.reserve(numkeys); - curve_first_key.reserve(numcurves); - curve_shader.reserve(numcurves); + curve_keys.reserve(numkeys); + curve_radius.reserve(numkeys); + curve_first_key.reserve(numcurves); + curve_shader.reserve(numcurves); - curve_attributes.resize(true); + curve_attributes.resize(true); } void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners) { - subd_faces.resize(numfaces); - subd_face_corners.resize(numcorners); - num_ngons = num_ngons_; + subd_faces.resize(numfaces); + subd_face_corners.resize(numcorners); + num_ngons = num_ngons_; - subd_attributes.resize(); + subd_attributes.resize(); } void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners) { - subd_faces.reserve(numfaces); - subd_face_corners.reserve(numcorners); - num_ngons = num_ngons_; + subd_faces.reserve(numfaces); + subd_face_corners.reserve(numcorners); + num_ngons = num_ngons_; - subd_attributes.resize(true); + subd_attributes.resize(true); } void Mesh::clear(bool preserve_voxel_data) { - /* clear all verts and triangles */ - verts.clear(); - triangles.clear(); - shader.clear(); - smooth.clear(); + /* clear all verts and triangles */ + verts.clear(); + triangles.clear(); + shader.clear(); + smooth.clear(); - triangle_patch.clear(); - vert_patch_uv.clear(); + triangle_patch.clear(); + vert_patch_uv.clear(); - curve_keys.clear(); - curve_radius.clear(); - curve_first_key.clear(); - curve_shader.clear(); + curve_keys.clear(); + curve_radius.clear(); + curve_first_key.clear(); + curve_shader.clear(); - subd_faces.clear(); - subd_face_corners.clear(); + subd_faces.clear(); + subd_face_corners.clear(); - num_subd_verts = 0; + num_subd_verts = 0; - subd_creases.clear(); + subd_creases.clear(); - curve_attributes.clear(); - subd_attributes.clear(); - attributes.clear(preserve_voxel_data); + curve_attributes.clear(); + subd_attributes.clear(); + attributes.clear(preserve_voxel_data); - used_shaders.clear(); + used_shaders.clear(); - if(!preserve_voxel_data) { - geometry_flags = GEOMETRY_NONE; - } + if (!preserve_voxel_data) { + geometry_flags = GEOMETRY_NONE; + } - transform_applied = false; - transform_negative_scaled = false; - transform_normal = transform_identity(); + transform_applied = false; + transform_negative_scaled = false; + transform_normal = transform_identity(); - delete patch_table; - patch_table = NULL; + delete patch_table; + patch_table = NULL; } void Mesh::add_vertex(float3 P) { - verts.push_back_reserved(P); + verts.push_back_reserved(P); - if(subd_faces.size()) { - vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f)); - } + if (subd_faces.size()) { + vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f)); + } } void Mesh::add_vertex_slow(float3 P) { - verts.push_back_slow(P); + verts.push_back_slow(P); - if(subd_faces.size()) { - vert_patch_uv.push_back_slow(make_float2(0.0f, 0.0f)); - } + if (subd_faces.size()) { + vert_patch_uv.push_back_slow(make_float2(0.0f, 0.0f)); + } } void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) { - triangles.push_back_reserved(v0); - triangles.push_back_reserved(v1); - triangles.push_back_reserved(v2); - shader.push_back_reserved(shader_); - smooth.push_back_reserved(smooth_); + triangles.push_back_reserved(v0); + triangles.push_back_reserved(v1); + triangles.push_back_reserved(v2); + shader.push_back_reserved(shader_); + smooth.push_back_reserved(smooth_); - if(subd_faces.size()) { - triangle_patch.push_back_reserved(-1); - } + if (subd_faces.size()) { + triangle_patch.push_back_reserved(-1); + } } void Mesh::add_curve_key(float3 co, float radius) { - curve_keys.push_back_reserved(co); - curve_radius.push_back_reserved(radius); + curve_keys.push_back_reserved(co); + curve_radius.push_back_reserved(radius); } void Mesh::add_curve(int first_key, int shader) { - curve_first_key.push_back_reserved(first_key); - curve_shader.push_back_reserved(shader); + curve_first_key.push_back_reserved(first_key); + curve_shader.push_back_reserved(shader); } -void Mesh::add_subd_face(int* corners, int num_corners, int shader_, bool smooth_) +void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth_) { - int start_corner = subd_face_corners.size(); + int start_corner = subd_face_corners.size(); - for(int i = 0; i < num_corners; i++) { - subd_face_corners.push_back_reserved(corners[i]); - } + for (int i = 0; i < num_corners; i++) { + subd_face_corners.push_back_reserved(corners[i]); + } - int ptex_offset = 0; + int ptex_offset = 0; - if(subd_faces.size()) { - SubdFace& s = subd_faces[subd_faces.size()-1]; - ptex_offset = s.ptex_offset + s.num_ptex_faces(); - } + if (subd_faces.size()) { + SubdFace &s = subd_faces[subd_faces.size() - 1]; + ptex_offset = s.ptex_offset + s.num_ptex_faces(); + } - SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset}; - subd_faces.push_back_reserved(face); + SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset}; + subd_faces.push_back_reserved(face); } void Mesh::compute_bounds() { - BoundBox bnds = BoundBox::empty; - size_t verts_size = verts.size(); - size_t curve_keys_size = curve_keys.size(); + BoundBox bnds = BoundBox::empty; + size_t verts_size = verts.size(); + size_t curve_keys_size = curve_keys.size(); - if(verts_size + curve_keys_size > 0) { - for(size_t i = 0; i < verts_size; i++) - bnds.grow(verts[i]); + if (verts_size + curve_keys_size > 0) { + for (size_t i = 0; i < verts_size; i++) + bnds.grow(verts[i]); - for(size_t i = 0; i < curve_keys_size; i++) - bnds.grow(curve_keys[i], curve_radius[i]); + for (size_t i = 0; i < curve_keys_size; i++) + bnds.grow(curve_keys[i], curve_radius[i]); - Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if(use_motion_blur && attr) { - size_t steps_size = verts.size() * (motion_steps - 1); - float3 *vert_steps = attr->data_float3(); + Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (use_motion_blur && attr) { + size_t steps_size = verts.size() * (motion_steps - 1); + float3 *vert_steps = attr->data_float3(); - for(size_t i = 0; i < steps_size; i++) - bnds.grow(vert_steps[i]); - } + for (size_t i = 0; i < steps_size; i++) + bnds.grow(vert_steps[i]); + } - Attribute *curve_attr = curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if(use_motion_blur && curve_attr) { - size_t steps_size = curve_keys.size() * (motion_steps - 1); - float3 *key_steps = curve_attr->data_float3(); + Attribute *curve_attr = curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (use_motion_blur && curve_attr) { + size_t steps_size = curve_keys.size() * (motion_steps - 1); + float3 *key_steps = curve_attr->data_float3(); - for(size_t i = 0; i < steps_size; i++) - bnds.grow(key_steps[i]); - } + for (size_t i = 0; i < steps_size; i++) + bnds.grow(key_steps[i]); + } - if(!bnds.valid()) { - bnds = BoundBox::empty; + if (!bnds.valid()) { + bnds = BoundBox::empty; - /* skip nan or inf coordinates */ - for(size_t i = 0; i < verts_size; i++) - bnds.grow_safe(verts[i]); + /* skip nan or inf coordinates */ + for (size_t i = 0; i < verts_size; i++) + bnds.grow_safe(verts[i]); - for(size_t i = 0; i < curve_keys_size; i++) - bnds.grow_safe(curve_keys[i], curve_radius[i]); + for (size_t i = 0; i < curve_keys_size; i++) + bnds.grow_safe(curve_keys[i], curve_radius[i]); - if(use_motion_blur && attr) { - size_t steps_size = verts.size() * (motion_steps - 1); - float3 *vert_steps = attr->data_float3(); + if (use_motion_blur && attr) { + size_t steps_size = verts.size() * (motion_steps - 1); + float3 *vert_steps = attr->data_float3(); - for(size_t i = 0; i < steps_size; i++) - bnds.grow_safe(vert_steps[i]); - } + for (size_t i = 0; i < steps_size; i++) + bnds.grow_safe(vert_steps[i]); + } - if(use_motion_blur && curve_attr) { - size_t steps_size = curve_keys.size() * (motion_steps - 1); - float3 *key_steps = curve_attr->data_float3(); + if (use_motion_blur && curve_attr) { + size_t steps_size = curve_keys.size() * (motion_steps - 1); + float3 *key_steps = curve_attr->data_float3(); - for(size_t i = 0; i < steps_size; i++) - bnds.grow_safe(key_steps[i]); - } - } - } + for (size_t i = 0; i < steps_size; i++) + bnds.grow_safe(key_steps[i]); + } + } + } - if(!bnds.valid()) { - /* empty mesh */ - bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); - } + if (!bnds.valid()) { + /* empty mesh */ + bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); + } - bounds = bnds; + bounds = bnds; } void Mesh::add_face_normals() { - /* don't compute if already there */ - if(attributes.find(ATTR_STD_FACE_NORMAL)) - return; + /* don't compute if already there */ + if (attributes.find(ATTR_STD_FACE_NORMAL)) + return; - /* get attributes */ - Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL); - float3 *fN = attr_fN->data_float3(); + /* get attributes */ + Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL); + float3 *fN = attr_fN->data_float3(); - /* compute face normals */ - size_t triangles_size = num_triangles(); + /* compute face normals */ + size_t triangles_size = num_triangles(); - if(triangles_size) { - float3 *verts_ptr = verts.data(); + if (triangles_size) { + float3 *verts_ptr = verts.data(); - for(size_t i = 0; i < triangles_size; i++) { - fN[i] = get_triangle(i).compute_normal(verts_ptr); - } - } + for (size_t i = 0; i < triangles_size; i++) { + fN[i] = get_triangle(i).compute_normal(verts_ptr); + } + } - /* expected to be in local space */ - if(transform_applied) { - Transform ntfm = transform_inverse(transform_normal); + /* expected to be in local space */ + if (transform_applied) { + Transform ntfm = transform_inverse(transform_normal); - for(size_t i = 0; i < triangles_size; i++) - fN[i] = normalize(transform_direction(&ntfm, fN[i])); - } + for (size_t i = 0; i < triangles_size; i++) + fN[i] = normalize(transform_direction(&ntfm, fN[i])); + } } void Mesh::add_vertex_normals() { - bool flip = transform_negative_scaled; - size_t verts_size = verts.size(); - size_t triangles_size = num_triangles(); - - /* static vertex normals */ - if(!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) { - /* get attributes */ - Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL); - Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL); - - float3 *fN = attr_fN->data_float3(); - float3 *vN = attr_vN->data_float3(); - - /* compute vertex normals */ - memset(vN, 0, verts.size()*sizeof(float3)); - - for(size_t i = 0; i < triangles_size; i++) { - for(size_t j = 0; j < 3; j++) { - vN[get_triangle(i).v[j]] += fN[i]; - } - } - - for(size_t i = 0; i < verts_size; i++) { - vN[i] = normalize(vN[i]); - if(flip) { - vN[i] = -vN[i]; - } - } - } - - /* motion vertex normals */ - Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - - if(has_motion_blur() && attr_mP && !attr_mN && triangles_size) { - /* create attribute */ - attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL); - - for(int step = 0; step < motion_steps - 1; step++) { - float3 *mP = attr_mP->data_float3() + step*verts.size(); - float3 *mN = attr_mN->data_float3() + step*verts.size(); - - /* compute */ - memset(mN, 0, verts.size()*sizeof(float3)); - - for(size_t i = 0; i < triangles_size; i++) { - for(size_t j = 0; j < 3; j++) { - float3 fN = get_triangle(i).compute_normal(mP); - mN[get_triangle(i).v[j]] += fN; - } - } - - for(size_t i = 0; i < verts_size; i++) { - mN[i] = normalize(mN[i]); - if(flip) { - mN[i] = -mN[i]; - } - } - } - } - - /* subd vertex normals */ - if(!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && subd_faces.size()) { - /* get attributes */ - Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL); - float3 *vN = attr_vN->data_float3(); - - /* compute vertex normals */ - memset(vN, 0, verts.size()*sizeof(float3)); - - for(size_t i = 0; i < subd_faces.size(); i++) { - SubdFace& face = subd_faces[i]; - float3 fN = face.normal(this); - - for(size_t j = 0; j < face.num_corners; j++) { - size_t corner = subd_face_corners[face.start_corner+j]; - vN[corner] += fN; - } - } - - for(size_t i = 0; i < verts_size; i++) { - vN[i] = normalize(vN[i]); - if(flip) { - vN[i] = -vN[i]; - } - } - } + bool flip = transform_negative_scaled; + size_t verts_size = verts.size(); + size_t triangles_size = num_triangles(); + + /* static vertex normals */ + if (!attributes.find(ATTR_STD_VERTEX_NORMAL) && triangles_size) { + /* get attributes */ + Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL); + Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL); + + float3 *fN = attr_fN->data_float3(); + float3 *vN = attr_vN->data_float3(); + + /* compute vertex normals */ + memset(vN, 0, verts.size() * sizeof(float3)); + + for (size_t i = 0; i < triangles_size; i++) { + for (size_t j = 0; j < 3; j++) { + vN[get_triangle(i).v[j]] += fN[i]; + } + } + + for (size_t i = 0; i < verts_size; i++) { + vN[i] = normalize(vN[i]); + if (flip) { + vN[i] = -vN[i]; + } + } + } + + /* motion vertex normals */ + Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + + if (has_motion_blur() && attr_mP && !attr_mN && triangles_size) { + /* create attribute */ + attr_mN = attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL); + + for (int step = 0; step < motion_steps - 1; step++) { + float3 *mP = attr_mP->data_float3() + step * verts.size(); + float3 *mN = attr_mN->data_float3() + step * verts.size(); + + /* compute */ + memset(mN, 0, verts.size() * sizeof(float3)); + + for (size_t i = 0; i < triangles_size; i++) { + for (size_t j = 0; j < 3; j++) { + float3 fN = get_triangle(i).compute_normal(mP); + mN[get_triangle(i).v[j]] += fN; + } + } + + for (size_t i = 0; i < verts_size; i++) { + mN[i] = normalize(mN[i]); + if (flip) { + mN[i] = -mN[i]; + } + } + } + } + + /* subd vertex normals */ + if (!subd_attributes.find(ATTR_STD_VERTEX_NORMAL) && subd_faces.size()) { + /* get attributes */ + Attribute *attr_vN = subd_attributes.add(ATTR_STD_VERTEX_NORMAL); + float3 *vN = attr_vN->data_float3(); + + /* compute vertex normals */ + memset(vN, 0, verts.size() * sizeof(float3)); + + for (size_t i = 0; i < subd_faces.size(); i++) { + SubdFace &face = subd_faces[i]; + float3 fN = face.normal(this); + + for (size_t j = 0; j < face.num_corners; j++) { + size_t corner = subd_face_corners[face.start_corner + j]; + vN[corner] += fN; + } + } + + for (size_t i = 0; i < verts_size; i++) { + vN[i] = normalize(vN[i]); + if (flip) { + vN[i] = -vN[i]; + } + } + } } void Mesh::add_undisplaced() { - AttributeSet& attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes; + AttributeSet &attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes; - /* don't compute if already there */ - if(attrs.find(ATTR_STD_POSITION_UNDISPLACED)) { - return; - } + /* don't compute if already there */ + if (attrs.find(ATTR_STD_POSITION_UNDISPLACED)) { + return; + } - /* get attribute */ - Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED); - attr->flags |= ATTR_SUBDIVIDED; + /* get attribute */ + Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED); + attr->flags |= ATTR_SUBDIVIDED; - float3 *data = attr->data_float3(); + float3 *data = attr->data_float3(); - /* copy verts */ - size_t size = attr->buffer_size(this, (subdivision_type == SUBDIVISION_NONE) ? ATTR_PRIM_TRIANGLE : ATTR_PRIM_SUBD); + /* copy verts */ + size_t size = attr->buffer_size( + this, (subdivision_type == SUBDIVISION_NONE) ? ATTR_PRIM_TRIANGLE : ATTR_PRIM_SUBD); - /* Center points for ngons aren't stored in Mesh::verts but are included in size since they will be - * calculated later, we subtract them from size here so we don't have an overflow while copying. - */ - size -= num_ngons * attr->data_sizeof(); + /* Center points for ngons aren't stored in Mesh::verts but are included in size since they will be + * calculated later, we subtract them from size here so we don't have an overflow while copying. + */ + size -= num_ngons * attr->data_sizeof(); - if(size) { - memcpy(data, verts.data(), size); - } + if (size) { + memcpy(data, verts.data(), size); + } } void Mesh::pack_shaders(Scene *scene, uint *tri_shader) { - uint shader_id = 0; - uint last_shader = -1; - bool last_smooth = false; + uint shader_id = 0; + uint last_shader = -1; + bool last_smooth = false; - size_t triangles_size = num_triangles(); - int *shader_ptr = shader.data(); + size_t triangles_size = num_triangles(); + int *shader_ptr = shader.data(); - for(size_t i = 0; i < triangles_size; i++) { - if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) { - last_shader = shader_ptr[i]; - last_smooth = smooth[i]; - Shader *shader = (last_shader < used_shaders.size()) ? - used_shaders[last_shader] : scene->default_surface; - shader_id = scene->shader_manager->get_shader_id(shader, last_smooth); - } + for (size_t i = 0; i < triangles_size; i++) { + if (shader_ptr[i] != last_shader || last_smooth != smooth[i]) { + last_shader = shader_ptr[i]; + last_smooth = smooth[i]; + Shader *shader = (last_shader < used_shaders.size()) ? used_shaders[last_shader] : + scene->default_surface; + shader_id = scene->shader_manager->get_shader_id(shader, last_smooth); + } - tri_shader[i] = shader_id; - } + tri_shader[i] = shader_id; + } } void Mesh::pack_normals(float4 *vnormal) { - Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); - if(attr_vN == NULL) { - /* Happens on objects with just hair. */ - return; - } + Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); + if (attr_vN == NULL) { + /* Happens on objects with just hair. */ + return; + } - bool do_transform = transform_applied; - Transform ntfm = transform_normal; + bool do_transform = transform_applied; + Transform ntfm = transform_normal; - float3 *vN = attr_vN->data_float3(); - size_t verts_size = verts.size(); + float3 *vN = attr_vN->data_float3(); + size_t verts_size = verts.size(); - for(size_t i = 0; i < verts_size; i++) { - float3 vNi = vN[i]; + for (size_t i = 0; i < verts_size; i++) { + float3 vNi = vN[i]; - if(do_transform) - vNi = safe_normalize(transform_direction(&ntfm, vNi)); + if (do_transform) + vNi = safe_normalize(transform_direction(&ntfm, vNi)); - vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f); - } + vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f); + } } -void Mesh::pack_verts(const vector<uint>& tri_prim_index, +void Mesh::pack_verts(const vector<uint> &tri_prim_index, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv, size_t vert_offset, size_t tri_offset) { - size_t verts_size = verts.size(); + size_t verts_size = verts.size(); - if(verts_size && subd_faces.size()) { - float2 *vert_patch_uv_ptr = vert_patch_uv.data(); + if (verts_size && subd_faces.size()) { + float2 *vert_patch_uv_ptr = vert_patch_uv.data(); - for(size_t i = 0; i < verts_size; i++) { - tri_patch_uv[i] = vert_patch_uv_ptr[i]; - } - } + for (size_t i = 0; i < verts_size; i++) { + tri_patch_uv[i] = vert_patch_uv_ptr[i]; + } + } - size_t triangles_size = num_triangles(); + size_t triangles_size = num_triangles(); - for(size_t i = 0; i < triangles_size; i++) { - Triangle t = get_triangle(i); - tri_vindex[i] = make_uint4(t.v[0] + vert_offset, - t.v[1] + vert_offset, - t.v[2] + vert_offset, - tri_prim_index[i + tri_offset]); + for (size_t i = 0; i < triangles_size; i++) { + Triangle t = get_triangle(i); + tri_vindex[i] = make_uint4(t.v[0] + vert_offset, + t.v[1] + vert_offset, + t.v[2] + vert_offset, + tri_prim_index[i + tri_offset]); - tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i]*8 + patch_offset); - } + tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i] * 8 + patch_offset); + } } -void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset) +void Mesh::pack_curves(Scene *scene, + float4 *curve_key_co, + float4 *curve_data, + size_t curvekey_offset) { - size_t curve_keys_size = curve_keys.size(); + size_t curve_keys_size = curve_keys.size(); - /* pack curve keys */ - if(curve_keys_size) { - float3 *keys_ptr = curve_keys.data(); - float *radius_ptr = curve_radius.data(); + /* pack curve keys */ + if (curve_keys_size) { + float3 *keys_ptr = curve_keys.data(); + float *radius_ptr = curve_radius.data(); - for(size_t i = 0; i < curve_keys_size; i++) - curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]); - } + for (size_t i = 0; i < curve_keys_size; i++) + curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]); + } - /* pack curve segments */ - size_t curve_num = num_curves(); + /* pack curve segments */ + size_t curve_num = num_curves(); - for(size_t i = 0; i < curve_num; i++) { - Curve curve = get_curve(i); - int shader_id = curve_shader[i]; - Shader *shader = (shader_id < used_shaders.size()) ? - used_shaders[shader_id] : scene->default_surface; - shader_id = scene->shader_manager->get_shader_id(shader, false); + for (size_t i = 0; i < curve_num; i++) { + Curve curve = get_curve(i); + int shader_id = curve_shader[i]; + Shader *shader = (shader_id < used_shaders.size()) ? used_shaders[shader_id] : + scene->default_surface; + shader_id = scene->shader_manager->get_shader_id(shader, false); - curve_data[i] = make_float4( - __int_as_float(curve.first_key + curvekey_offset), - __int_as_float(curve.num_keys), - __int_as_float(shader_id), - 0.0f); - } + curve_data[i] = make_float4(__int_as_float(curve.first_key + curvekey_offset), + __int_as_float(curve.num_keys), + __int_as_float(shader_id), + 0.0f); + } } void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset) { - size_t num_faces = subd_faces.size(); - int ngons = 0; - - for(size_t f = 0; f < num_faces; f++) { - SubdFace face = subd_faces[f]; - - if(face.is_quad()) { - int c[4]; - memcpy(c, &subd_face_corners[face.start_corner], sizeof(int)*4); - - *(patch_data++) = c[0] + vert_offset; - *(patch_data++) = c[1] + vert_offset; - *(patch_data++) = c[2] + vert_offset; - *(patch_data++) = c[3] + vert_offset; - - *(patch_data++) = f+face_offset; - *(patch_data++) = face.num_corners; - *(patch_data++) = face.start_corner + corner_offset; - *(patch_data++) = 0; - } - else { - for(int i = 0; i < face.num_corners; i++) { - int c[4]; - c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)]; - c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)]; - c[2] = verts.size() - num_subd_verts + ngons; - c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)]; - - *(patch_data++) = c[0] + vert_offset; - *(patch_data++) = c[1] + vert_offset; - *(patch_data++) = c[2] + vert_offset; - *(patch_data++) = c[3] + vert_offset; - - *(patch_data++) = f+face_offset; - *(patch_data++) = face.num_corners | (i << 16); - *(patch_data++) = face.start_corner + corner_offset; - *(patch_data++) = subd_face_corners.size() + ngons + corner_offset; - } - - ngons++; - } - } -} - -void Mesh::compute_bvh(Device *device, - DeviceScene *dscene, - SceneParams *params, - Progress *progress, - int n, - int total) -{ - if(progress->get_cancel()) - return; - - compute_bounds(); - - if(need_build_bvh()) { - string msg = "Updating Mesh BVH "; - if(name == "") - msg += string_printf("%u/%u", (uint)(n+1), (uint)total); - else - msg += string_printf("%s %u/%u", name.c_str(), (uint)(n+1), (uint)total); - - Object object; - object.mesh = this; - - vector<Object*> objects; - objects.push_back(&object); - - if(bvh && !need_update_rebuild) { - progress->set_status(msg, "Refitting BVH"); - bvh->objects = objects; - bvh->refit(*progress); - } - else { - progress->set_status(msg, "Building BVH"); - - BVHParams bparams; - bparams.use_spatial_split = params->use_bvh_spatial_split; - bparams.bvh_layout = BVHParams::best_bvh_layout( - params->bvh_layout, - device->get_bvh_layout_mask()); - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - params->use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = params->num_bvh_time_steps; - bparams.num_motion_curve_steps = params->num_bvh_time_steps; - bparams.bvh_type = params->bvh_type; - bparams.curve_flags = dscene->data.curve.curveflags; - bparams.curve_subdivisions = dscene->data.curve.subdivisions; - - delete bvh; - bvh = BVH::create(bparams, objects); - MEM_GUARDED_CALL(progress, bvh->build, *progress); - } - } - - need_update = false; - need_update_rebuild = false; + size_t num_faces = subd_faces.size(); + int ngons = 0; + + for (size_t f = 0; f < num_faces; f++) { + SubdFace face = subd_faces[f]; + + if (face.is_quad()) { + int c[4]; + memcpy(c, &subd_face_corners[face.start_corner], sizeof(int) * 4); + + *(patch_data++) = c[0] + vert_offset; + *(patch_data++) = c[1] + vert_offset; + *(patch_data++) = c[2] + vert_offset; + *(patch_data++) = c[3] + vert_offset; + + *(patch_data++) = f + face_offset; + *(patch_data++) = face.num_corners; + *(patch_data++) = face.start_corner + corner_offset; + *(patch_data++) = 0; + } + else { + for (int i = 0; i < face.num_corners; i++) { + int c[4]; + c[0] = subd_face_corners[face.start_corner + mod(i + 0, face.num_corners)]; + c[1] = subd_face_corners[face.start_corner + mod(i + 1, face.num_corners)]; + c[2] = verts.size() - num_subd_verts + ngons; + c[3] = subd_face_corners[face.start_corner + mod(i - 1, face.num_corners)]; + + *(patch_data++) = c[0] + vert_offset; + *(patch_data++) = c[1] + vert_offset; + *(patch_data++) = c[2] + vert_offset; + *(patch_data++) = c[3] + vert_offset; + + *(patch_data++) = f + face_offset; + *(patch_data++) = face.num_corners | (i << 16); + *(patch_data++) = face.start_corner + corner_offset; + *(patch_data++) = subd_face_corners.size() + ngons + corner_offset; + } + + ngons++; + } + } +} + +void Mesh::compute_bvh( + Device *device, DeviceScene *dscene, SceneParams *params, Progress *progress, int n, int total) +{ + if (progress->get_cancel()) + return; + + compute_bounds(); + + if (need_build_bvh()) { + string msg = "Updating Mesh BVH "; + if (name == "") + msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); + else + msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); + + Object object; + object.mesh = this; + + vector<Object *> objects; + objects.push_back(&object); + + if (bvh && !need_update_rebuild) { + progress->set_status(msg, "Refitting BVH"); + bvh->objects = objects; + bvh->refit(*progress); + } + else { + progress->set_status(msg, "Building BVH"); + + BVHParams bparams; + bparams.use_spatial_split = params->use_bvh_spatial_split; + bparams.bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout, + device->get_bvh_layout_mask()); + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = params->num_bvh_time_steps; + bparams.num_motion_curve_steps = params->num_bvh_time_steps; + bparams.bvh_type = params->bvh_type; + bparams.curve_flags = dscene->data.curve.curveflags; + bparams.curve_subdivisions = dscene->data.curve.subdivisions; + + delete bvh; + bvh = BVH::create(bparams, objects); + MEM_GUARDED_CALL(progress, bvh->build, *progress); + } + } + + need_update = false; + need_update_rebuild = false; } void Mesh::tag_update(Scene *scene, bool rebuild) { - need_update = true; + need_update = true; - if(rebuild) { - need_update_rebuild = true; - scene->light_manager->need_update = true; - } - else { - foreach(Shader *shader, used_shaders) - if(shader->has_surface_emission) - scene->light_manager->need_update = true; - } + if (rebuild) { + need_update_rebuild = true; + scene->light_manager->need_update = true; + } + else { + foreach (Shader *shader, used_shaders) + if (shader->has_surface_emission) + scene->light_manager->need_update = true; + } - scene->mesh_manager->need_update = true; - scene->object_manager->need_update = true; + scene->mesh_manager->need_update = true; + scene->object_manager->need_update = true; } bool Mesh::has_motion_blur() const { - return (use_motion_blur && - (attributes.find(ATTR_STD_MOTION_VERTEX_POSITION) || - curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))); + return (use_motion_blur && (attributes.find(ATTR_STD_MOTION_VERTEX_POSITION) || + curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))); } bool Mesh::has_true_displacement() const { - foreach(Shader *shader, used_shaders) { - if(shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) { - return true; - } - } + foreach (Shader *shader, used_shaders) { + if (shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) { + return true; + } + } - return false; + return false; } float Mesh::motion_time(int step) const { - return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; + return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; } int Mesh::motion_step(float time) const { - if(motion_steps > 1) { - int attr_step = 0; + if (motion_steps > 1) { + int attr_step = 0; - for(int step = 0; step < motion_steps; step++) { - float step_time = motion_time(step); - if(step_time == time) { - return attr_step; - } + for (int step = 0; step < motion_steps; step++) { + float step_time = motion_time(step); + if (step_time == time) { + return attr_step; + } - /* Center step is stored in a separate attribute. */ - if(step != motion_steps / 2) { - attr_step++; - } - } - } + /* Center step is stored in a separate attribute. */ + if (step != motion_steps / 2) { + attr_step++; + } + } + } - return -1; + return -1; } bool Mesh::need_build_bvh() const { - return !transform_applied || has_surface_bssrdf; + return !transform_applied || has_surface_bssrdf; } bool Mesh::is_instanced() const { - /* Currently we treat subsurface objects as instanced. - * - * While it might be not very optimal for ray traversal, it avoids having - * duplicated BVH in the memory, saving quite some space. - */ - return !transform_applied || has_surface_bssrdf; + /* Currently we treat subsurface objects as instanced. + * + * While it might be not very optimal for ray traversal, it avoids having + * duplicated BVH in the memory, saving quite some space. + */ + return !transform_applied || has_surface_bssrdf; } /* Mesh Manager */ MeshManager::MeshManager() { - need_update = true; - need_flags_update = true; + need_update = true; + need_flags_update = true; } MeshManager::~MeshManager() { } -void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<AttributeRequestSet>& mesh_attributes) +void MeshManager::update_osl_attributes(Device *device, + Scene *scene, + vector<AttributeRequestSet> &mesh_attributes) { #ifdef WITH_OSL - /* for OSL, a hash map is used to lookup the attribute by name. */ - OSLGlobals *og = (OSLGlobals*)device->osl_memory(); - - og->object_name_map.clear(); - og->attribute_map.clear(); - og->object_names.clear(); - - og->attribute_map.resize(scene->objects.size()*ATTR_PRIM_TYPES); - - for(size_t i = 0; i < scene->objects.size(); i++) { - /* set object name to object index map */ - Object *object = scene->objects[i]; - og->object_name_map[object->name] = i; - og->object_names.push_back(object->name); - - /* set object attributes */ - foreach(ParamValue& attr, object->attributes) { - OSLGlobals::Attribute osl_attr; - - osl_attr.type = attr.type(); - osl_attr.desc.element = ATTR_ELEMENT_OBJECT; - osl_attr.value = attr; - osl_attr.desc.offset = 0; - osl_attr.desc.flags = 0; - - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr; - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr; - } - - /* find mesh attributes */ - size_t j; - - for(j = 0; j < scene->meshes.size(); j++) - if(scene->meshes[j] == object->mesh) - break; - - AttributeRequestSet& attributes = mesh_attributes[j]; - - /* set object attributes */ - foreach(AttributeRequest& req, attributes.requests) { - OSLGlobals::Attribute osl_attr; - - if(req.triangle_desc.element != ATTR_ELEMENT_NONE) { - osl_attr.desc = req.triangle_desc; - - if(req.triangle_type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else if(req.triangle_type == TypeDesc::TypeMatrix) - osl_attr.type = TypeDesc::TypeMatrix; - else if(req.triangle_type == TypeFloat2) - osl_attr.type = TypeFloat2; - else - osl_attr.type = TypeDesc::TypeColor; - - if(req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr; - } - else if(req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr; - } - } - - if(req.curve_desc.element != ATTR_ELEMENT_NONE) { - osl_attr.desc = req.curve_desc; - - if(req.curve_type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else if(req.curve_type == TypeDesc::TypeMatrix) - osl_attr.type = TypeDesc::TypeMatrix; - else - osl_attr.type = TypeDesc::TypeColor; - - if(req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr; - } - else if(req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; - } - } - - if(req.subd_desc.element != ATTR_ELEMENT_NONE) { - osl_attr.desc = req.subd_desc; - - if(req.subd_type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else if(req.subd_type == TypeDesc::TypeMatrix) - osl_attr.type = TypeDesc::TypeMatrix; - else - osl_attr.type = TypeDesc::TypeColor; - - if(req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr; - } - else if(req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr; - } - } - } - } + /* for OSL, a hash map is used to lookup the attribute by name. */ + OSLGlobals *og = (OSLGlobals *)device->osl_memory(); + + og->object_name_map.clear(); + og->attribute_map.clear(); + og->object_names.clear(); + + og->attribute_map.resize(scene->objects.size() * ATTR_PRIM_TYPES); + + for (size_t i = 0; i < scene->objects.size(); i++) { + /* set object name to object index map */ + Object *object = scene->objects[i]; + og->object_name_map[object->name] = i; + og->object_names.push_back(object->name); + + /* set object attributes */ + foreach (ParamValue &attr, object->attributes) { + OSLGlobals::Attribute osl_attr; + + osl_attr.type = attr.type(); + osl_attr.desc.element = ATTR_ELEMENT_OBJECT; + osl_attr.value = attr; + osl_attr.desc.offset = 0; + osl_attr.desc.flags = 0; + + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr; + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr; + } + + /* find mesh attributes */ + size_t j; + + for (j = 0; j < scene->meshes.size(); j++) + if (scene->meshes[j] == object->mesh) + break; + + AttributeRequestSet &attributes = mesh_attributes[j]; + + /* set object attributes */ + foreach (AttributeRequest &req, attributes.requests) { + OSLGlobals::Attribute osl_attr; + + if (req.triangle_desc.element != ATTR_ELEMENT_NONE) { + osl_attr.desc = req.triangle_desc; + + if (req.triangle_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if (req.triangle_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else if (req.triangle_type == TypeFloat2) + osl_attr.type = TypeFloat2; + else + osl_attr.type = TypeDesc::TypeColor; + + if (req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr; + } + else if (req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr; + } + } + + if (req.curve_desc.element != ATTR_ELEMENT_NONE) { + osl_attr.desc = req.curve_desc; + + if (req.curve_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if (req.curve_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else + osl_attr.type = TypeDesc::TypeColor; + + if (req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr; + } + else if (req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; + } + } + + if (req.subd_desc.element != ATTR_ELEMENT_NONE) { + osl_attr.desc = req.subd_desc; + + if (req.subd_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if (req.subd_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else + osl_attr.type = TypeDesc::TypeColor; + + if (req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr; + } + else if (req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr; + } + } + } + } #else - (void) device; - (void) scene; - (void) mesh_attributes; + (void)device; + (void)scene; + (void)mesh_attributes; #endif } -void MeshManager::update_svm_attributes(Device *, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes) -{ - /* for SVM, the attributes_map table is used to lookup the offset of an - * attribute, based on a unique shader attribute id. */ - - /* compute array stride */ - int attr_map_size = 0; +void MeshManager::update_svm_attributes(Device *, + DeviceScene *dscene, + Scene *scene, + vector<AttributeRequestSet> &mesh_attributes) +{ + /* for SVM, the attributes_map table is used to lookup the offset of an + * attribute, based on a unique shader attribute id. */ + + /* compute array stride */ + int attr_map_size = 0; + + for (size_t i = 0; i < scene->meshes.size(); i++) { + Mesh *mesh = scene->meshes[i]; + mesh->attr_map_offset = attr_map_size; + attr_map_size += (mesh_attributes[i].size() + 1) * ATTR_PRIM_TYPES; + } - for(size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - mesh->attr_map_offset = attr_map_size; - attr_map_size += (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES; - } + if (attr_map_size == 0) + return; - if(attr_map_size == 0) - return; + /* create attribute map */ + uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size); + memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint)); - /* create attribute map */ - uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size); - memset(attr_map, 0, dscene->attributes_map.size()*sizeof(uint)); + for (size_t i = 0; i < scene->meshes.size(); i++) { + Mesh *mesh = scene->meshes[i]; + AttributeRequestSet &attributes = mesh_attributes[i]; - for(size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - AttributeRequestSet& attributes = mesh_attributes[i]; + /* set object attributes */ + int index = mesh->attr_map_offset; - /* set object attributes */ - int index = mesh->attr_map_offset; + foreach (AttributeRequest &req, attributes.requests) { + uint id; - foreach(AttributeRequest& req, attributes.requests) { - uint id; + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); - if(req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); + if (mesh->num_triangles()) { + attr_map[index].x = id; + attr_map[index].y = req.triangle_desc.element; + attr_map[index].z = as_uint(req.triangle_desc.offset); - if(mesh->num_triangles()) { - attr_map[index].x = id; - attr_map[index].y = req.triangle_desc.element; - attr_map[index].z = as_uint(req.triangle_desc.offset); + if (req.triangle_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (req.triangle_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (req.triangle_type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else + attr_map[index].w = NODE_ATTR_FLOAT3; - if(req.triangle_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if(req.triangle_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if(req.triangle_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else - attr_map[index].w = NODE_ATTR_FLOAT3; + attr_map[index].w |= req.triangle_desc.flags << 8; + } - attr_map[index].w |= req.triangle_desc.flags << 8; - } + index++; - index++; + if (mesh->num_curves()) { + attr_map[index].x = id; + attr_map[index].y = req.curve_desc.element; + attr_map[index].z = as_uint(req.curve_desc.offset); - if(mesh->num_curves()) { - attr_map[index].x = id; - attr_map[index].y = req.curve_desc.element; - attr_map[index].z = as_uint(req.curve_desc.offset); + if (req.curve_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (req.curve_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (req.curve_type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else + attr_map[index].w = NODE_ATTR_FLOAT3; - if(req.curve_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if(req.curve_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if(req.curve_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else - attr_map[index].w = NODE_ATTR_FLOAT3; + attr_map[index].w |= req.curve_desc.flags << 8; + } - attr_map[index].w |= req.curve_desc.flags << 8; - } + index++; - index++; + if (mesh->subd_faces.size()) { + attr_map[index].x = id; + attr_map[index].y = req.subd_desc.element; + attr_map[index].z = as_uint(req.subd_desc.offset); - if(mesh->subd_faces.size()) { - attr_map[index].x = id; - attr_map[index].y = req.subd_desc.element; - attr_map[index].z = as_uint(req.subd_desc.offset); + if (req.subd_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (req.subd_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (req.subd_type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else + attr_map[index].w = NODE_ATTR_FLOAT3; - if(req.subd_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if(req.subd_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if(req.subd_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else - attr_map[index].w = NODE_ATTR_FLOAT3; + attr_map[index].w |= req.subd_desc.flags << 8; + } - attr_map[index].w |= req.subd_desc.flags << 8; - } + index++; + } - index++; - } - - /* terminator */ - for(int j = 0; j < ATTR_PRIM_TYPES; j++) { - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; - - index++; - } - } - - /* copy to device */ - dscene->attributes_map.copy_to_device(); + /* terminator */ + for (int j = 0; j < ATTR_PRIM_TYPES; j++) { + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; + + index++; + } + } + + /* copy to device */ + dscene->attributes_map.copy_to_device(); } static void update_attribute_element_size(Mesh *mesh, Attribute *mattr, AttributePrimitive prim, size_t *attr_float_size, - size_t *attr_float2_size, + size_t *attr_float2_size, size_t *attr_float3_size, size_t *attr_uchar4_size) { - if(mattr) { - size_t size = mattr->element_size(mesh, prim); - - if(mattr->element == ATTR_ELEMENT_VOXEL) { - /* pass */ - } - else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - *attr_uchar4_size += size; - } - else if(mattr->type == TypeDesc::TypeFloat) { - *attr_float_size += size; - } - else if(mattr->type == TypeFloat2) { - *attr_float2_size += size; - } - else if(mattr->type == TypeDesc::TypeMatrix) { - *attr_float3_size += size * 4; - } - else { - *attr_float3_size += size; - } - } + if (mattr) { + size_t size = mattr->element_size(mesh, prim); + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* pass */ + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + *attr_uchar4_size += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + *attr_float_size += size; + } + else if (mattr->type == TypeFloat2) { + *attr_float2_size += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + *attr_float3_size += size * 4; + } + else { + *attr_float3_size += size; + } + } } static void update_attribute_element_offset(Mesh *mesh, - device_vector<float>& attr_float, - size_t& attr_float_offset, - device_vector<float2>& attr_float2, - size_t& attr_float2_offset, - device_vector<float4>& attr_float3, - size_t& attr_float3_offset, - device_vector<uchar4>& attr_uchar4, - size_t& attr_uchar4_offset, + device_vector<float> &attr_float, + size_t &attr_float_offset, + device_vector<float2> &attr_float2, + size_t &attr_float2_offset, + device_vector<float4> &attr_float3, + size_t &attr_float3_offset, + device_vector<uchar4> &attr_uchar4, + size_t &attr_uchar4_offset, Attribute *mattr, AttributePrimitive prim, - TypeDesc& type, - AttributeDescriptor& desc) -{ - if(mattr) { - /* store element and type */ - desc.element = mattr->element; - desc.flags = mattr->flags; - type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(mesh, prim); - - AttributeElement& element = desc.element; - int& offset = desc.offset; - - if(mattr->element == ATTR_ELEMENT_VOXEL) { - /* store slot in offset value */ - VoxelAttribute *voxel_data = mattr->data_voxel(); - offset = voxel_data->slot; - } - else if(mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - uchar4 *data = mattr->data_uchar4(); - offset = attr_uchar4_offset; - - assert(attr_uchar4.size() >= offset + size); - for(size_t k = 0; k < size; k++) { - attr_uchar4[offset+k] = data[k]; - } - attr_uchar4_offset += size; - } - else if(mattr->type == TypeDesc::TypeFloat) { - float *data = mattr->data_float(); - offset = attr_float_offset; - - assert(attr_float.size() >= offset + size); - for(size_t k = 0; k < size; k++) { - attr_float[offset+k] = data[k]; - } - attr_float_offset += size; - } - else if(mattr->type == TypeFloat2) { - float2 *data = mattr->data_float2(); - offset = attr_float2_offset; - - assert(attr_float2.size() >= offset + size); - for(size_t k = 0; k < size; k++) { - attr_float2[offset+k] = data[k]; - } - attr_float2_offset += size; - } - else if(mattr->type == TypeDesc::TypeMatrix) { - Transform *tfm = mattr->data_transform(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size * 3); - for(size_t k = 0; k < size*3; k++) { - attr_float3[offset+k] = (&tfm->x)[k]; - } - attr_float3_offset += size * 3; - } - else { - float4 *data = mattr->data_float4(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size); - for(size_t k = 0; k < size; k++) { - attr_float3[offset+k] = data[k]; - } - attr_float3_offset += size; - } - - /* mesh vertex/curve index is global, not per object, so we sneak - * a correction for that in here */ - if(mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && desc.flags & ATTR_SUBDIVIDED) { - /* indices for subdivided attributes are retrieved - * from patch table so no need for correction here*/ - } - else if(element == ATTR_ELEMENT_VERTEX) - offset -= mesh->vert_offset; - else if(element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= mesh->vert_offset; - else if(element == ATTR_ELEMENT_FACE) { - if(prim == ATTR_PRIM_TRIANGLE) - offset -= mesh->tri_offset; - else - offset -= mesh->face_offset; - } - else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { - if(prim == ATTR_PRIM_TRIANGLE) - offset -= 3*mesh->tri_offset; - else - offset -= mesh->corner_offset; - } - else if(element == ATTR_ELEMENT_CURVE) - offset -= mesh->curve_offset; - else if(element == ATTR_ELEMENT_CURVE_KEY) - offset -= mesh->curvekey_offset; - else if(element == ATTR_ELEMENT_CURVE_KEY_MOTION) - offset -= mesh->curvekey_offset; - } - else { - /* attribute not found */ - desc.element = ATTR_ELEMENT_NONE; - desc.offset = 0; - } -} - -void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) -{ - progress.set_status("Updating Mesh", "Computing attributes"); - - /* gather per mesh requested attributes. as meshes may have multiple - * shaders assigned, this merges the requested attributes that have - * been set per shader by the shader manager */ - vector<AttributeRequestSet> mesh_attributes(scene->meshes.size()); - - for(size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - - scene->need_global_attributes(mesh_attributes[i]); - - foreach(Shader *shader, mesh->used_shaders) { - mesh_attributes[i].add(shader->attributes); - } - } - - /* mesh attribute are stored in a single array per data type. here we fill - * those arrays, and set the offset and element type to create attribute - * maps next */ - - /* Pre-allocate attributes to avoid arrays re-allocation which would - * take 2x of overall attribute memory usage. - */ - size_t attr_float_size = 0; - size_t attr_float2_size = 0; - size_t attr_float3_size = 0; - size_t attr_uchar4_size = 0; - for(size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - AttributeRequestSet& attributes = mesh_attributes[i]; - foreach(AttributeRequest& req, attributes.requests) { - Attribute *triangle_mattr = mesh->attributes.find(req); - Attribute *curve_mattr = mesh->curve_attributes.find(req); - Attribute *subd_mattr = mesh->subd_attributes.find(req); - - update_attribute_element_size(mesh, - triangle_mattr, - ATTR_PRIM_TRIANGLE, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_uchar4_size); - update_attribute_element_size(mesh, - curve_mattr, - ATTR_PRIM_CURVE, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_uchar4_size); - update_attribute_element_size(mesh, - subd_mattr, - ATTR_PRIM_SUBD, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_uchar4_size); - } - } - - dscene->attributes_float.alloc(attr_float_size); - dscene->attributes_float2.alloc(attr_float2_size); - dscene->attributes_float3.alloc(attr_float3_size); - dscene->attributes_uchar4.alloc(attr_uchar4_size); - - size_t attr_float_offset = 0; - size_t attr_float2_offset = 0; - size_t attr_float3_offset = 0; - size_t attr_uchar4_offset = 0; - - /* Fill in attributes. */ - for(size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - AttributeRequestSet& attributes = mesh_attributes[i]; - - /* todo: we now store std and name attributes from requests even if - * they actually refer to the same mesh attributes, optimize */ - foreach(AttributeRequest& req, attributes.requests) { - Attribute *triangle_mattr = mesh->attributes.find(req); - Attribute *curve_mattr = mesh->curve_attributes.find(req); - Attribute *subd_mattr = mesh->subd_attributes.find(req); - - update_attribute_element_offset(mesh, - dscene->attributes_float, attr_float_offset, - dscene->attributes_float2, attr_float2_offset, - dscene->attributes_float3, attr_float3_offset, - dscene->attributes_uchar4, attr_uchar4_offset, - triangle_mattr, - ATTR_PRIM_TRIANGLE, - req.triangle_type, - req.triangle_desc); - - update_attribute_element_offset(mesh, - dscene->attributes_float, attr_float_offset, - dscene->attributes_float2, attr_float2_offset, - dscene->attributes_float3, attr_float3_offset, - dscene->attributes_uchar4, attr_uchar4_offset, - curve_mattr, - ATTR_PRIM_CURVE, - req.curve_type, - req.curve_desc); - - update_attribute_element_offset(mesh, - dscene->attributes_float, attr_float_offset, - dscene->attributes_float2, attr_float2_offset, - dscene->attributes_float3, attr_float3_offset, - dscene->attributes_uchar4, attr_uchar4_offset, - subd_mattr, - ATTR_PRIM_SUBD, - req.subd_type, - req.subd_desc); - - if(progress.get_cancel()) return; - } - } - - /* create attribute lookup maps */ - if(scene->shader_manager->use_osl()) - update_osl_attributes(device, scene, mesh_attributes); - - update_svm_attributes(device, dscene, scene, mesh_attributes); - - if(progress.get_cancel()) return; - - /* copy to device */ - progress.set_status("Updating Mesh", "Copying Attributes to device"); - - if(dscene->attributes_float.size()) { - dscene->attributes_float.copy_to_device(); - } - if(dscene->attributes_float2.size()) { - dscene->attributes_float2.copy_to_device(); - } - if(dscene->attributes_float3.size()) { - dscene->attributes_float3.copy_to_device(); - } - if(dscene->attributes_uchar4.size()) { - dscene->attributes_uchar4.copy_to_device(); - } - - if(progress.get_cancel()) return; - - /* After mesh attributes and patch tables have been copied to device memory, - * we need to update offsets in the objects. */ - scene->object_manager->device_update_mesh_offsets(device, dscene, scene); + TypeDesc &type, + AttributeDescriptor &desc) +{ + if (mattr) { + /* store element and type */ + desc.element = mattr->element; + desc.flags = mattr->flags; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size(mesh, prim); + + AttributeElement &element = desc.element; + int &offset = desc.offset; + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* store slot in offset value */ + VoxelAttribute *voxel_data = mattr->data_voxel(); + offset = voxel_data->slot; + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + uchar4 *data = mattr->data_uchar4(); + offset = attr_uchar4_offset; + + assert(attr_uchar4.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_uchar4[offset + k] = data[k]; + } + attr_uchar4_offset += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float_offset; + + assert(attr_float.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_float[offset + k] = data[k]; + } + attr_float_offset += size; + } + else if (mattr->type == TypeFloat2) { + float2 *data = mattr->data_float2(); + offset = attr_float2_offset; + + assert(attr_float2.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_float2[offset + k] = data[k]; + } + attr_float2_offset += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + Transform *tfm = mattr->data_transform(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size * 3); + for (size_t k = 0; k < size * 3; k++) { + attr_float3[offset + k] = (&tfm->x)[k]; + } + attr_float3_offset += size * 3; + } + else { + float4 *data = mattr->data_float4(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_float3[offset + k] = data[k]; + } + attr_float3_offset += size; + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && + desc.flags & ATTR_SUBDIVIDED) { + /* indices for subdivided attributes are retrieved + * from patch table so no need for correction here*/ + } + else if (element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_FACE) { + if (prim == ATTR_PRIM_TRIANGLE) + offset -= mesh->tri_offset; + else + offset -= mesh->face_offset; + } + else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if (prim == ATTR_PRIM_TRIANGLE) + offset -= 3 * mesh->tri_offset; + else + offset -= mesh->corner_offset; + } + else if (element == ATTR_ELEMENT_CURVE) + offset -= mesh->curve_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY) + offset -= mesh->curvekey_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) + offset -= mesh->curvekey_offset; + } + else { + /* attribute not found */ + desc.element = ATTR_ELEMENT_NONE; + desc.offset = 0; + } +} + +void MeshManager::device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + progress.set_status("Updating Mesh", "Computing attributes"); + + /* gather per mesh requested attributes. as meshes may have multiple + * shaders assigned, this merges the requested attributes that have + * been set per shader by the shader manager */ + vector<AttributeRequestSet> mesh_attributes(scene->meshes.size()); + + for (size_t i = 0; i < scene->meshes.size(); i++) { + Mesh *mesh = scene->meshes[i]; + + scene->need_global_attributes(mesh_attributes[i]); + + foreach (Shader *shader, mesh->used_shaders) { + mesh_attributes[i].add(shader->attributes); + } + } + + /* mesh attribute are stored in a single array per data type. here we fill + * those arrays, and set the offset and element type to create attribute + * maps next */ + + /* Pre-allocate attributes to avoid arrays re-allocation which would + * take 2x of overall attribute memory usage. + */ + size_t attr_float_size = 0; + size_t attr_float2_size = 0; + size_t attr_float3_size = 0; + size_t attr_uchar4_size = 0; + for (size_t i = 0; i < scene->meshes.size(); i++) { + Mesh *mesh = scene->meshes[i]; + AttributeRequestSet &attributes = mesh_attributes[i]; + foreach (AttributeRequest &req, attributes.requests) { + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *curve_mattr = mesh->curve_attributes.find(req); + Attribute *subd_mattr = mesh->subd_attributes.find(req); + + update_attribute_element_size(mesh, + triangle_mattr, + ATTR_PRIM_TRIANGLE, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + update_attribute_element_size(mesh, + curve_mattr, + ATTR_PRIM_CURVE, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + update_attribute_element_size(mesh, + subd_mattr, + ATTR_PRIM_SUBD, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + } + } + + dscene->attributes_float.alloc(attr_float_size); + dscene->attributes_float2.alloc(attr_float2_size); + dscene->attributes_float3.alloc(attr_float3_size); + dscene->attributes_uchar4.alloc(attr_uchar4_size); + + size_t attr_float_offset = 0; + size_t attr_float2_offset = 0; + size_t attr_float3_offset = 0; + size_t attr_uchar4_offset = 0; + + /* Fill in attributes. */ + for (size_t i = 0; i < scene->meshes.size(); i++) { + Mesh *mesh = scene->meshes[i]; + AttributeRequestSet &attributes = mesh_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach (AttributeRequest &req, attributes.requests) { + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *curve_mattr = mesh->curve_attributes.find(req); + Attribute *subd_mattr = mesh->subd_attributes.find(req); + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + triangle_mattr, + ATTR_PRIM_TRIANGLE, + req.triangle_type, + req.triangle_desc); + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + curve_mattr, + ATTR_PRIM_CURVE, + req.curve_type, + req.curve_desc); + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + subd_mattr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_desc); + + if (progress.get_cancel()) + return; + } + } + + /* create attribute lookup maps */ + if (scene->shader_manager->use_osl()) + update_osl_attributes(device, scene, mesh_attributes); + + update_svm_attributes(device, dscene, scene, mesh_attributes); + + if (progress.get_cancel()) + return; + + /* copy to device */ + progress.set_status("Updating Mesh", "Copying Attributes to device"); + + if (dscene->attributes_float.size()) { + dscene->attributes_float.copy_to_device(); + } + if (dscene->attributes_float2.size()) { + dscene->attributes_float2.copy_to_device(); + } + if (dscene->attributes_float3.size()) { + dscene->attributes_float3.copy_to_device(); + } + if (dscene->attributes_uchar4.size()) { + dscene->attributes_uchar4.copy_to_device(); + } + + if (progress.get_cancel()) + return; + + /* After mesh attributes and patch tables have been copied to device memory, + * we need to update offsets in the objects. */ + scene->object_manager->device_update_mesh_offsets(device, dscene, scene); } void MeshManager::mesh_calc_offset(Scene *scene) { - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - - size_t patch_size = 0; - size_t face_size = 0; - size_t corner_size = 0; - - foreach(Mesh *mesh, scene->meshes) { - mesh->vert_offset = vert_size; - mesh->tri_offset = tri_size; - - mesh->curvekey_offset = curve_key_size; - mesh->curve_offset = curve_size; - - mesh->patch_offset = patch_size; - mesh->face_offset = face_size; - mesh->corner_offset = corner_size; - - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - curve_key_size += mesh->curve_keys.size(); - curve_size += mesh->num_curves(); - - if(mesh->subd_faces.size()) { - Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1]; - patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; - - /* patch tables are stored in same array so include them in patch_size */ - if(mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - face_size += mesh->subd_faces.size(); - corner_size += mesh->subd_face_corners.size(); - } -} - -void MeshManager::device_update_mesh(Device *, - DeviceScene *dscene, - Scene *scene, - bool for_displacement, - Progress& progress) -{ - /* Count. */ - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - - size_t patch_size = 0; - - foreach(Mesh *mesh, scene->meshes) { - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - curve_key_size += mesh->curve_keys.size(); - curve_size += mesh->num_curves(); - - if(mesh->subd_faces.size()) { - Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1]; - patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; - - /* patch tables are stored in same array so include them in patch_size */ - if(mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - } - - /* Create mapping from triangle to primitive triangle array. */ - vector<uint> tri_prim_index(tri_size); - if(for_displacement) { - /* For displacement kernels we do some trickery to make them believe - * we've got all required data ready. However, that data is different - * from final render kernels since we don't have BVH yet, so can't - * really use same semantic of arrays. - */ - foreach(Mesh *mesh, scene->meshes) { - for(size_t i = 0; i < mesh->num_triangles(); ++i) { - tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset); - } - } - } - else { - for(size_t i = 0; i < dscene->prim_index.size(); ++i) { - if((dscene->prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { - tri_prim_index[dscene->prim_index[i]] = dscene->prim_tri_index[i]; - } - } - } - - /* Fill in all the arrays. */ - if(tri_size != 0) { - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); - - uint *tri_shader = dscene->tri_shader.alloc(tri_size); - float4 *vnormal = dscene->tri_vnormal.alloc(vert_size); - uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size); - uint *tri_patch = dscene->tri_patch.alloc(tri_size); - float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); - - foreach(Mesh *mesh, scene->meshes) { - mesh->pack_shaders(scene, - &tri_shader[mesh->tri_offset]); - mesh->pack_normals(&vnormal[mesh->vert_offset]); - mesh->pack_verts(tri_prim_index, - &tri_vindex[mesh->tri_offset], - &tri_patch[mesh->tri_offset], - &tri_patch_uv[mesh->vert_offset], - mesh->vert_offset, - mesh->tri_offset); - if(progress.get_cancel()) return; - } - - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); - - dscene->tri_shader.copy_to_device(); - dscene->tri_vnormal.copy_to_device(); - dscene->tri_vindex.copy_to_device(); - dscene->tri_patch.copy_to_device(); - dscene->tri_patch_uv.copy_to_device(); - } - - if(curve_size != 0) { - progress.set_status("Updating Mesh", "Copying Strands to device"); - - float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); - float4 *curves = dscene->curves.alloc(curve_size); - - foreach(Mesh *mesh, scene->meshes) { - mesh->pack_curves(scene, &curve_keys[mesh->curvekey_offset], &curves[mesh->curve_offset], mesh->curvekey_offset); - if(progress.get_cancel()) return; - } - - dscene->curve_keys.copy_to_device(); - dscene->curves.copy_to_device(); - } - - if(patch_size != 0) { - progress.set_status("Updating Mesh", "Copying Patches to device"); - - uint *patch_data = dscene->patches.alloc(patch_size); - - foreach(Mesh *mesh, scene->meshes) { - mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_offset); - - if(mesh->patch_table) { - mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], mesh->patch_table_offset); - } - - if(progress.get_cancel()) return; - } - - dscene->patches.copy_to_device(); - } - - if(for_displacement) { - float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3); - foreach(Mesh *mesh, scene->meshes) { - for(size_t i = 0; i < mesh->num_triangles(); ++i) { - Mesh::Triangle t = mesh->get_triangle(i); - size_t offset = 3 * (i + mesh->tri_offset); - prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]); - prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]); - prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]); - } - } - dscene->prim_tri_verts.copy_to_device(); - } -} - -void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) -{ - /* bvh build */ - progress.set_status("Updating Scene BVH", "Building"); - - BVHParams bparams; - bparams.top_level = true; - bparams.bvh_layout = BVHParams::best_bvh_layout( - scene->params.bvh_layout, - device->get_bvh_layout_mask()); - bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - scene->params.use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; - bparams.bvh_type = scene->params.bvh_type; - bparams.curve_flags = dscene->data.curve.curveflags; - bparams.curve_subdivisions = dscene->data.curve.subdivisions; - - VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) - << " layout."; + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + + size_t patch_size = 0; + size_t face_size = 0; + size_t corner_size = 0; + + foreach (Mesh *mesh, scene->meshes) { + mesh->vert_offset = vert_size; + mesh->tri_offset = tri_size; + + mesh->curvekey_offset = curve_key_size; + mesh->curve_offset = curve_size; + + mesh->patch_offset = patch_size; + mesh->face_offset = face_size; + mesh->corner_offset = corner_size; + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + curve_key_size += mesh->curve_keys.size(); + curve_size += mesh->num_curves(); + + if (mesh->subd_faces.size()) { + Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + + /* patch tables are stored in same array so include them in patch_size */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + face_size += mesh->subd_faces.size(); + corner_size += mesh->subd_face_corners.size(); + } +} + +void MeshManager::device_update_mesh( + Device *, DeviceScene *dscene, Scene *scene, bool for_displacement, Progress &progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + + size_t patch_size = 0; + + foreach (Mesh *mesh, scene->meshes) { + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + curve_key_size += mesh->curve_keys.size(); + curve_size += mesh->num_curves(); + + if (mesh->subd_faces.size()) { + Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + + /* patch tables are stored in same array so include them in patch_size */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + } + + /* Create mapping from triangle to primitive triangle array. */ + vector<uint> tri_prim_index(tri_size); + if (for_displacement) { + /* For displacement kernels we do some trickery to make them believe + * we've got all required data ready. However, that data is different + * from final render kernels since we don't have BVH yet, so can't + * really use same semantic of arrays. + */ + foreach (Mesh *mesh, scene->meshes) { + for (size_t i = 0; i < mesh->num_triangles(); ++i) { + tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset); + } + } + } + else { + for (size_t i = 0; i < dscene->prim_index.size(); ++i) { + if ((dscene->prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + tri_prim_index[dscene->prim_index[i]] = dscene->prim_tri_index[i]; + } + } + } + + /* Fill in all the arrays. */ + if (tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); + + uint *tri_shader = dscene->tri_shader.alloc(tri_size); + float4 *vnormal = dscene->tri_vnormal.alloc(vert_size); + uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size); + uint *tri_patch = dscene->tri_patch.alloc(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); + + foreach (Mesh *mesh, scene->meshes) { + mesh->pack_shaders(scene, &tri_shader[mesh->tri_offset]); + mesh->pack_normals(&vnormal[mesh->vert_offset]); + mesh->pack_verts(tri_prim_index, + &tri_vindex[mesh->tri_offset], + &tri_patch[mesh->tri_offset], + &tri_patch_uv[mesh->vert_offset], + mesh->vert_offset, + mesh->tri_offset); + if (progress.get_cancel()) + return; + } + + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + dscene->tri_shader.copy_to_device(); + dscene->tri_vnormal.copy_to_device(); + dscene->tri_vindex.copy_to_device(); + dscene->tri_patch.copy_to_device(); + dscene->tri_patch_uv.copy_to_device(); + } + + if (curve_size != 0) { + progress.set_status("Updating Mesh", "Copying Strands to device"); + + float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); + float4 *curves = dscene->curves.alloc(curve_size); + + foreach (Mesh *mesh, scene->meshes) { + mesh->pack_curves(scene, + &curve_keys[mesh->curvekey_offset], + &curves[mesh->curve_offset], + mesh->curvekey_offset); + if (progress.get_cancel()) + return; + } + + dscene->curve_keys.copy_to_device(); + dscene->curves.copy_to_device(); + } + + if (patch_size != 0) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.alloc(patch_size); + + foreach (Mesh *mesh, scene->meshes) { + mesh->pack_patches(&patch_data[mesh->patch_offset], + mesh->vert_offset, + mesh->face_offset, + mesh->corner_offset); + + if (mesh->patch_table) { + mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], + mesh->patch_table_offset); + } + + if (progress.get_cancel()) + return; + } + + dscene->patches.copy_to_device(); + } + + if (for_displacement) { + float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3); + foreach (Mesh *mesh, scene->meshes) { + for (size_t i = 0; i < mesh->num_triangles(); ++i) { + Mesh::Triangle t = mesh->get_triangle(i); + size_t offset = 3 * (i + mesh->tri_offset); + prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]); + prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]); + prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]); + } + } + dscene->prim_tri_verts.copy_to_device(); + } +} + +void MeshManager::device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* bvh build */ + progress.set_status("Updating Scene BVH", "Building"); + + BVHParams bparams; + bparams.top_level = true; + bparams.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, + device->get_bvh_layout_mask()); + bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; + bparams.bvh_type = scene->params.bvh_type; + bparams.curve_flags = dscene->data.curve.curveflags; + bparams.curve_subdivisions = dscene->data.curve.subdivisions; + + VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; #ifdef WITH_EMBREE - if(bparams.bvh_layout == BVH_LAYOUT_EMBREE) { - if(dscene->data.bvh.scene) { - BVHEmbree::destroy(dscene->data.bvh.scene); - } - } + if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { + if (dscene->data.bvh.scene) { + BVHEmbree::destroy(dscene->data.bvh.scene); + } + } #endif - BVH *bvh = BVH::create(bparams, scene->objects); - bvh->build(progress, &device->stats); + BVH *bvh = BVH::create(bparams, scene->objects); + bvh->build(progress, &device->stats); - if(progress.get_cancel()) { + if (progress.get_cancel()) { #ifdef WITH_EMBREE - if(bparams.bvh_layout == BVH_LAYOUT_EMBREE) { - if(dscene->data.bvh.scene) { - BVHEmbree::destroy(dscene->data.bvh.scene); - } - } + if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { + if (dscene->data.bvh.scene) { + BVHEmbree::destroy(dscene->data.bvh.scene); + } + } #endif - delete bvh; - return; - } - - /* copy to device */ - progress.set_status("Updating Scene BVH", "Copying BVH to device"); - - PackedBVH& pack = bvh->pack; - - if(pack.nodes.size()) { - dscene->bvh_nodes.steal_data(pack.nodes); - dscene->bvh_nodes.copy_to_device(); - } - if(pack.leaf_nodes.size()) { - dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); - dscene->bvh_leaf_nodes.copy_to_device(); - } - if(pack.object_node.size()) { - dscene->object_node.steal_data(pack.object_node); - dscene->object_node.copy_to_device(); - } - if(pack.prim_tri_index.size()) { - dscene->prim_tri_index.steal_data(pack.prim_tri_index); - dscene->prim_tri_index.copy_to_device(); - } - if(pack.prim_tri_verts.size()) { - dscene->prim_tri_verts.steal_data(pack.prim_tri_verts); - dscene->prim_tri_verts.copy_to_device(); - } - if(pack.prim_type.size()) { - dscene->prim_type.steal_data(pack.prim_type); - dscene->prim_type.copy_to_device(); - } - if(pack.prim_visibility.size()) { - dscene->prim_visibility.steal_data(pack.prim_visibility); - dscene->prim_visibility.copy_to_device(); - } - if(pack.prim_index.size()) { - dscene->prim_index.steal_data(pack.prim_index); - dscene->prim_index.copy_to_device(); - } - if(pack.prim_object.size()) { - dscene->prim_object.steal_data(pack.prim_object); - dscene->prim_object.copy_to_device(); - } - if(pack.prim_time.size()) { - dscene->prim_time.steal_data(pack.prim_time); - dscene->prim_time.copy_to_device(); - } - - dscene->data.bvh.root = pack.root_index; - dscene->data.bvh.bvh_layout = bparams.bvh_layout; - dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); - + delete bvh; + return; + } + + /* copy to device */ + progress.set_status("Updating Scene BVH", "Copying BVH to device"); + + PackedBVH &pack = bvh->pack; + + if (pack.nodes.size()) { + dscene->bvh_nodes.steal_data(pack.nodes); + dscene->bvh_nodes.copy_to_device(); + } + if (pack.leaf_nodes.size()) { + dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); + dscene->bvh_leaf_nodes.copy_to_device(); + } + if (pack.object_node.size()) { + dscene->object_node.steal_data(pack.object_node); + dscene->object_node.copy_to_device(); + } + if (pack.prim_tri_index.size()) { + dscene->prim_tri_index.steal_data(pack.prim_tri_index); + dscene->prim_tri_index.copy_to_device(); + } + if (pack.prim_tri_verts.size()) { + dscene->prim_tri_verts.steal_data(pack.prim_tri_verts); + dscene->prim_tri_verts.copy_to_device(); + } + if (pack.prim_type.size()) { + dscene->prim_type.steal_data(pack.prim_type); + dscene->prim_type.copy_to_device(); + } + if (pack.prim_visibility.size()) { + dscene->prim_visibility.steal_data(pack.prim_visibility); + dscene->prim_visibility.copy_to_device(); + } + if (pack.prim_index.size()) { + dscene->prim_index.steal_data(pack.prim_index); + dscene->prim_index.copy_to_device(); + } + if (pack.prim_object.size()) { + dscene->prim_object.steal_data(pack.prim_object); + dscene->prim_object.copy_to_device(); + } + if (pack.prim_time.size()) { + dscene->prim_time.steal_data(pack.prim_time); + dscene->prim_time.copy_to_device(); + } + + dscene->data.bvh.root = pack.root_index; + dscene->data.bvh.bvh_layout = bparams.bvh_layout; + dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); #ifdef WITH_EMBREE - if(bparams.bvh_layout == BVH_LAYOUT_EMBREE) { - dscene->data.bvh.scene = ((BVHEmbree*)bvh)->scene; - } - else { - dscene->data.bvh.scene = NULL; - } + if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { + dscene->data.bvh.scene = ((BVHEmbree *)bvh)->scene; + } + else { + dscene->data.bvh.scene = NULL; + } #endif - delete bvh; + delete bvh; } -void MeshManager::device_update_preprocess(Device *device, - Scene *scene, - Progress& progress) +void MeshManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) { - if(!need_update && !need_flags_update) { - return; - } + if (!need_update && !need_flags_update) { + return; + } - progress.set_status("Updating Meshes Flags"); + progress.set_status("Updating Meshes Flags"); - /* Update flags. */ - bool volume_images_updated = false; + /* Update flags. */ + bool volume_images_updated = false; - foreach(Mesh *mesh, scene->meshes) { - mesh->has_volume = false; + foreach (Mesh *mesh, scene->meshes) { + mesh->has_volume = false; - foreach(const Shader *shader, mesh->used_shaders) { - if(shader->has_volume) { - mesh->has_volume = true; - } - if(shader->has_surface_bssrdf) { - mesh->has_surface_bssrdf = true; - } - } + foreach (const Shader *shader, mesh->used_shaders) { + if (shader->has_volume) { + mesh->has_volume = true; + } + if (shader->has_surface_bssrdf) { + mesh->has_surface_bssrdf = true; + } + } - if(need_update && mesh->has_volume) { - /* Create volume meshes if there is voxel data. */ - bool has_voxel_attributes = false; + if (need_update && mesh->has_volume) { + /* Create volume meshes if there is voxel data. */ + bool has_voxel_attributes = false; - foreach(Attribute& attr, mesh->attributes.attributes) { - if(attr.element == ATTR_ELEMENT_VOXEL) { - has_voxel_attributes = true; - } - } + foreach (Attribute &attr, mesh->attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + has_voxel_attributes = true; + } + } - if(has_voxel_attributes) { - if(!volume_images_updated) { - progress.set_status("Updating Meshes Volume Bounds"); - device_update_volume_images(device, scene, progress); - volume_images_updated = true; - } + if (has_voxel_attributes) { + if (!volume_images_updated) { + progress.set_status("Updating Meshes Volume Bounds"); + device_update_volume_images(device, scene, progress); + volume_images_updated = true; + } - create_volume_mesh(scene, mesh, progress); - } - } - } + create_volume_mesh(scene, mesh, progress); + } + } + } - need_flags_update = false; + need_flags_update = false; } void MeshManager::device_update_displacement_images(Device *device, Scene *scene, - Progress& progress) -{ - progress.set_status("Updating Displacement Images"); - TaskPool pool; - ImageManager *image_manager = scene->image_manager; - set<int> bump_images; - foreach(Mesh *mesh, scene->meshes) { - if(mesh->need_update) { - foreach(Shader *shader, mesh->used_shaders) { - if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { - continue; - } - foreach(ShaderNode* node, shader->graph->nodes) { - if(node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) { - continue; - } - - ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode*>(node); - int slot = image_node->slot; - if(slot != -1) { - bump_images.insert(slot); - } - } - } - } - } - foreach(int slot, bump_images) { - pool.push(function_bind(&ImageManager::device_update_slot, - image_manager, - device, - scene, - slot, - &progress)); - } - pool.wait_work(); -} - -void MeshManager::device_update_volume_images(Device *device, - Scene *scene, - Progress& progress) -{ - progress.set_status("Updating Volume Images"); - TaskPool pool; - ImageManager *image_manager = scene->image_manager; - set<int> volume_images; - - foreach(Mesh *mesh, scene->meshes) { - if(!mesh->need_update) { - continue; - } - - foreach(Attribute& attr, mesh->attributes.attributes) { - if(attr.element != ATTR_ELEMENT_VOXEL) { - continue; - } - - VoxelAttribute *voxel = attr.data_voxel(); - - if(voxel->slot != -1) { - volume_images.insert(voxel->slot); - } - } - } - - foreach(int slot, volume_images) { - pool.push(function_bind(&ImageManager::device_update_slot, - image_manager, - device, - scene, - slot, - &progress)); - } - pool.wait_work(); -} - -void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) -{ - if(!need_update) - return; - - VLOG(1) << "Total " << scene->meshes.size() << " meshes."; - - bool true_displacement_used = false; - size_t total_tess_needed = 0; - - foreach(Mesh *mesh, scene->meshes) { - foreach(Shader *shader, mesh->used_shaders) { - if(shader->need_update_mesh) - mesh->need_update = true; - } - - if(mesh->need_update) { - /* Update normals. */ - mesh->add_face_normals(); - mesh->add_vertex_normals(); - - if(mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { - mesh->add_undisplaced(); - } - - /* Test if we need tessellation. */ - if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE && - mesh->num_subd_verts == 0 && - mesh->subd_params) - { - total_tess_needed++; - } - - /* Test if we need displacement. */ - if(mesh->has_true_displacement()) { - true_displacement_used = true; - } - - if(progress.get_cancel()) return; - } - } - - /* Tessellate meshes that are using subdivision */ - if(total_tess_needed) { - Camera *dicing_camera = scene->dicing_camera; - dicing_camera->update(scene); - - size_t i = 0; - foreach(Mesh *mesh, scene->meshes) { - if(mesh->need_update && - mesh->subdivision_type != Mesh::SUBDIVISION_NONE && - mesh->num_subd_verts == 0 && - mesh->subd_params) - { - string msg = "Tessellating "; - if(mesh->name == "") - msg += string_printf("%u/%u", (uint)(i+1), (uint)total_tess_needed); - else - msg += string_printf("%s %u/%u", mesh->name.c_str(), (uint)(i+1), (uint)total_tess_needed); - - progress.set_status("Updating Mesh", msg); - - mesh->subd_params->camera = dicing_camera; - DiagSplit dsplit(*mesh->subd_params); - mesh->tessellate(&dsplit); - - i++; - - if(progress.get_cancel()) return; - } - - } - } - - /* Update images needed for true displacement. */ - bool old_need_object_flags_update = false; - if(true_displacement_used) { - VLOG(1) << "Updating images used for true displacement."; - device_update_displacement_images(device, scene, progress); - old_need_object_flags_update = scene->object_manager->need_flags_update; - scene->object_manager->device_update_flags(device, - dscene, - scene, - progress, - false); - } - - /* Device update. */ - device_free(device, dscene); - - mesh_calc_offset(scene); - if(true_displacement_used) { - device_update_mesh(device, dscene, scene, true, progress); - } - if(progress.get_cancel()) return; - - device_update_attributes(device, dscene, scene, progress); - if(progress.get_cancel()) return; - - /* Update displacement. */ - bool displacement_done = false; - size_t num_bvh = 0; - - foreach(Mesh *mesh, scene->meshes) { - if(mesh->need_update) { - if(displace(device, dscene, scene, mesh, progress)) { - displacement_done = true; - } - - if(mesh->need_build_bvh()) { - num_bvh++; - } - } - - if(progress.get_cancel()) return; - } - - /* Device re-update after displacement. */ - if(displacement_done) { - device_free(device, dscene); - - device_update_attributes(device, dscene, scene, progress); - if(progress.get_cancel()) return; - } - - TaskPool pool; - - size_t i = 0; - foreach(Mesh *mesh, scene->meshes) { - if(mesh->need_update) { - pool.push(function_bind(&Mesh::compute_bvh, - mesh, - device, - dscene, - &scene->params, - &progress, - i, - num_bvh)); - if(mesh->need_build_bvh()) { - i++; - } - } - } - - TaskPool::Summary summary; - pool.wait_work(&summary); - VLOG(2) << "Objects BVH build pool statistics:\n" - << summary.full_report(); - - foreach(Shader *shader, scene->shaders) { - shader->need_update_mesh = false; - } - - Scene::MotionType need_motion = scene->need_motion(); - bool motion_blur = need_motion == Scene::MOTION_BLUR; - - /* Update objects. */ - vector<Object *> volume_objects; - foreach(Object *object, scene->objects) { - object->compute_bounds(motion_blur); - } - - if(progress.get_cancel()) return; - - device_update_bvh(device, dscene, scene, progress); - if(progress.get_cancel()) return; - - device_update_mesh(device, dscene, scene, false, progress); - if(progress.get_cancel()) return; - - need_update = false; - - if(true_displacement_used) { - /* Re-tag flags for update, so they're re-evaluated - * for meshes with correct bounding boxes. - * - * This wouldn't cause wrong results, just true - * displacement might be less optimal ot calculate. - */ - scene->object_manager->need_flags_update = old_need_object_flags_update; - } + Progress &progress) +{ + progress.set_status("Updating Displacement Images"); + TaskPool pool; + ImageManager *image_manager = scene->image_manager; + set<int> bump_images; + foreach (Mesh *mesh, scene->meshes) { + if (mesh->need_update) { + foreach (Shader *shader, mesh->used_shaders) { + if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { + continue; + } + foreach (ShaderNode *node, shader->graph->nodes) { + if (node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) { + continue; + } + + ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node); + int slot = image_node->slot; + if (slot != -1) { + bump_images.insert(slot); + } + } + } + } + } + foreach (int slot, bump_images) { + pool.push(function_bind( + &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress)); + } + pool.wait_work(); +} + +void MeshManager::device_update_volume_images(Device *device, Scene *scene, Progress &progress) +{ + progress.set_status("Updating Volume Images"); + TaskPool pool; + ImageManager *image_manager = scene->image_manager; + set<int> volume_images; + + foreach (Mesh *mesh, scene->meshes) { + if (!mesh->need_update) { + continue; + } + + foreach (Attribute &attr, mesh->attributes.attributes) { + if (attr.element != ATTR_ELEMENT_VOXEL) { + continue; + } + + VoxelAttribute *voxel = attr.data_voxel(); + + if (voxel->slot != -1) { + volume_images.insert(voxel->slot); + } + } + } + + foreach (int slot, volume_images) { + pool.push(function_bind( + &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress)); + } + pool.wait_work(); +} + +void MeshManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + if (!need_update) + return; + + VLOG(1) << "Total " << scene->meshes.size() << " meshes."; + + bool true_displacement_used = false; + size_t total_tess_needed = 0; + + foreach (Mesh *mesh, scene->meshes) { + foreach (Shader *shader, mesh->used_shaders) { + if (shader->need_update_mesh) + mesh->need_update = true; + } + + if (mesh->need_update) { + /* Update normals. */ + mesh->add_face_normals(); + mesh->add_vertex_normals(); + + if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { + mesh->add_undisplaced(); + } + + /* Test if we need tessellation. */ + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 && + mesh->subd_params) { + total_tess_needed++; + } + + /* Test if we need displacement. */ + if (mesh->has_true_displacement()) { + true_displacement_used = true; + } + + if (progress.get_cancel()) + return; + } + } + + /* Tessellate meshes that are using subdivision */ + if (total_tess_needed) { + Camera *dicing_camera = scene->dicing_camera; + dicing_camera->update(scene); + + size_t i = 0; + foreach (Mesh *mesh, scene->meshes) { + if (mesh->need_update && mesh->subdivision_type != Mesh::SUBDIVISION_NONE && + mesh->num_subd_verts == 0 && mesh->subd_params) { + string msg = "Tessellating "; + if (mesh->name == "") + msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed); + else + msg += string_printf( + "%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)total_tess_needed); + + progress.set_status("Updating Mesh", msg); + + mesh->subd_params->camera = dicing_camera; + DiagSplit dsplit(*mesh->subd_params); + mesh->tessellate(&dsplit); + + i++; + + if (progress.get_cancel()) + return; + } + } + } + + /* Update images needed for true displacement. */ + bool old_need_object_flags_update = false; + if (true_displacement_used) { + VLOG(1) << "Updating images used for true displacement."; + device_update_displacement_images(device, scene, progress); + old_need_object_flags_update = scene->object_manager->need_flags_update; + scene->object_manager->device_update_flags(device, dscene, scene, progress, false); + } + + /* Device update. */ + device_free(device, dscene); + + mesh_calc_offset(scene); + if (true_displacement_used) { + device_update_mesh(device, dscene, scene, true, progress); + } + if (progress.get_cancel()) + return; + + device_update_attributes(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + + /* Update displacement. */ + bool displacement_done = false; + size_t num_bvh = 0; + + foreach (Mesh *mesh, scene->meshes) { + if (mesh->need_update) { + if (displace(device, dscene, scene, mesh, progress)) { + displacement_done = true; + } + + if (mesh->need_build_bvh()) { + num_bvh++; + } + } + + if (progress.get_cancel()) + return; + } + + /* Device re-update after displacement. */ + if (displacement_done) { + device_free(device, dscene); + + device_update_attributes(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + } + + TaskPool pool; + + size_t i = 0; + foreach (Mesh *mesh, scene->meshes) { + if (mesh->need_update) { + pool.push(function_bind( + &Mesh::compute_bvh, mesh, device, dscene, &scene->params, &progress, i, num_bvh)); + if (mesh->need_build_bvh()) { + i++; + } + } + } + + TaskPool::Summary summary; + pool.wait_work(&summary); + VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); + + foreach (Shader *shader, scene->shaders) { + shader->need_update_mesh = false; + } + + Scene::MotionType need_motion = scene->need_motion(); + bool motion_blur = need_motion == Scene::MOTION_BLUR; + + /* Update objects. */ + vector<Object *> volume_objects; + foreach (Object *object, scene->objects) { + object->compute_bounds(motion_blur); + } + + if (progress.get_cancel()) + return; + + device_update_bvh(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + + device_update_mesh(device, dscene, scene, false, progress); + if (progress.get_cancel()) + return; + + need_update = false; + + if (true_displacement_used) { + /* Re-tag flags for update, so they're re-evaluated + * for meshes with correct bounding boxes. + * + * This wouldn't cause wrong results, just true + * displacement might be less optimal ot calculate. + */ + scene->object_manager->need_flags_update = old_need_object_flags_update; + } } void MeshManager::device_free(Device *device, DeviceScene *dscene) { - dscene->bvh_nodes.free(); - dscene->bvh_leaf_nodes.free(); - dscene->object_node.free(); - dscene->prim_tri_verts.free(); - dscene->prim_tri_index.free(); - dscene->prim_type.free(); - dscene->prim_visibility.free(); - dscene->prim_index.free(); - dscene->prim_object.free(); - dscene->prim_time.free(); - dscene->tri_shader.free(); - dscene->tri_vnormal.free(); - dscene->tri_vindex.free(); - dscene->tri_patch.free(); - dscene->tri_patch_uv.free(); - dscene->curves.free(); - dscene->curve_keys.free(); - dscene->patches.free(); - dscene->attributes_map.free(); - dscene->attributes_float.free(); - dscene->attributes_float2.free(); - dscene->attributes_float3.free(); - dscene->attributes_uchar4.free(); + dscene->bvh_nodes.free(); + dscene->bvh_leaf_nodes.free(); + dscene->object_node.free(); + dscene->prim_tri_verts.free(); + dscene->prim_tri_index.free(); + dscene->prim_type.free(); + dscene->prim_visibility.free(); + dscene->prim_index.free(); + dscene->prim_object.free(); + dscene->prim_time.free(); + dscene->tri_shader.free(); + dscene->tri_vnormal.free(); + dscene->tri_vindex.free(); + dscene->tri_patch.free(); + dscene->tri_patch_uv.free(); + dscene->curves.free(); + dscene->curve_keys.free(); + dscene->patches.free(); + dscene->attributes_map.free(); + dscene->attributes_float.free(); + dscene->attributes_float2.free(); + dscene->attributes_float3.free(); + dscene->attributes_uchar4.free(); #ifdef WITH_OSL - OSLGlobals *og = (OSLGlobals*)device->osl_memory(); + OSLGlobals *og = (OSLGlobals *)device->osl_memory(); - if(og) { - og->object_name_map.clear(); - og->attribute_map.clear(); - og->object_names.clear(); - } + if (og) { + og->object_name_map.clear(); + og->attribute_map.clear(); + og->object_names.clear(); + } #else - (void) device; + (void)device; #endif } void MeshManager::tag_update(Scene *scene) { - need_update = true; - scene->object_manager->need_update = true; + need_update = true; + scene->object_manager->need_update = true; } void MeshManager::collect_statistics(const Scene *scene, RenderStats *stats) { - foreach(Mesh *mesh, scene->meshes) { - stats->mesh.geometry.add_entry( - NamedSizeEntry(string(mesh->name.c_str()), - mesh->get_total_size_in_bytes())); - } + foreach (Mesh *mesh, scene->meshes) { + stats->mesh.geometry.add_entry( + NamedSizeEntry(string(mesh->name.c_str()), mesh->get_total_size_in_bytes())); + } } bool Mesh::need_attribute(Scene *scene, AttributeStandard std) { - if(std == ATTR_STD_NONE) - return false; + if (std == ATTR_STD_NONE) + return false; - if(scene->need_global_attribute(std)) - return true; + if (scene->need_global_attribute(std)) + return true; - foreach(Shader *shader, used_shaders) - if(shader->attributes.find(std)) - return true; + foreach (Shader *shader, used_shaders) + if (shader->attributes.find(std)) + return true; - return false; + return false; } bool Mesh::need_attribute(Scene * /*scene*/, ustring name) { - if(name == ustring()) - return false; + if (name == ustring()) + return false; - foreach(Shader *shader, used_shaders) - if(shader->attributes.find(name)) - return true; + foreach (Shader *shader, used_shaders) + if (shader->attributes.find(name)) + return true; - return false; + return false; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 789d1cc2b54..05c67ccb3b7 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -50,344 +50,352 @@ struct PackedPatchTable; /* Mesh */ class Mesh : public Node { -public: - NODE_DECLARE - - /* Mesh Triangle */ - struct Triangle { - int v[3]; - - void bounds_grow(const float3 *verts, BoundBox& bounds) const; - - void motion_verts(const float3 *verts, - const float3 *vert_steps, - size_t num_verts, - size_t num_steps, - float time, - float3 r_verts[3]) const; - - void verts_for_step(const float3 *verts, - const float3 *vert_steps, - size_t num_verts, - size_t num_steps, - size_t step, - float3 r_verts[3]) const; - - float3 compute_normal(const float3 *verts) const; - - bool valid(const float3 *verts) const; - }; - - Triangle get_triangle(size_t i) const - { - Triangle tri = {{triangles[i*3 + 0], - triangles[i*3 + 1], - triangles[i*3 + 2]}}; - return tri; - } - - size_t num_triangles() const - { - return triangles.size() / 3; - } - - /* Mesh Curve */ - struct Curve { - int first_key; - int num_keys; - - int num_segments() { return num_keys - 1; } - - void bounds_grow(const int k, - const float3 *curve_keys, - const float *curve_radius, - BoundBox& bounds) const; - void bounds_grow(float4 keys[4], BoundBox& bounds) const; - void bounds_grow(const int k, - const float3 *curve_keys, - const float *curve_radius, - const Transform& aligned_space, - BoundBox& bounds) const; - - void motion_keys(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - float time, - size_t k0, size_t k1, - float4 r_keys[2]) const; - void cardinal_motion_keys(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - float time, - size_t k0, size_t k1, - size_t k2, size_t k3, - float4 r_keys[4]) const; - - void keys_for_step(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - size_t step, - size_t k0, size_t k1, - float4 r_keys[2]) const; - void cardinal_keys_for_step(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - size_t step, - size_t k0, size_t k1, - size_t k2, size_t k3, - float4 r_keys[4]) const; - }; - - Curve get_curve(size_t i) const - { - int first = curve_first_key[i]; - int next_first = (i+1 < curve_first_key.size()) ? curve_first_key[i+1] : curve_keys.size(); - - Curve curve = {first, next_first - first}; - return curve; - } - - size_t num_curves() const - { - return curve_first_key.size(); - } - - /* Mesh SubdFace */ - struct SubdFace { - int start_corner; - int num_corners; - int shader; - bool smooth; - int ptex_offset; - - bool is_quad() { return num_corners == 4; } - float3 normal(const Mesh *mesh) const; - int num_ptex_faces() const { return num_corners == 4 ? 1 : num_corners; } - }; - - struct SubdEdgeCrease { - int v[2]; - float crease; - }; - - enum SubdivisionType { - SUBDIVISION_NONE, - SUBDIVISION_LINEAR, - SUBDIVISION_CATMULL_CLARK, - }; - - SubdivisionType subdivision_type; - - /* Mesh Data */ - enum GeometryFlags { - GEOMETRY_NONE = 0, - GEOMETRY_TRIANGLES = (1 << 0), - GEOMETRY_CURVES = (1 << 1), - }; - int geometry_flags; /* used to distinguish meshes with no verts - and meshed for which geometry is not created */ - - array<int> triangles; - array<float3> verts; - array<int> shader; - array<bool> smooth; - - /* used for storing patch info for subd triangles, only allocated if there are patches */ - array<int> triangle_patch; /* must be < 0 for non subd triangles */ - array<float2> vert_patch_uv; - - float volume_isovalue; - bool has_volume; /* Set in the device_update_flags(). */ - bool has_surface_bssrdf; /* Set in the device_update_flags(). */ - - array<float3> curve_keys; - array<float> curve_radius; - array<int> curve_first_key; - array<int> curve_shader; - - array<SubdFace> subd_faces; - array<int> subd_face_corners; - int num_ngons; - - array<SubdEdgeCrease> subd_creases; - - SubdParams *subd_params; - - vector<Shader*> used_shaders; - AttributeSet attributes; - AttributeSet curve_attributes; - AttributeSet subd_attributes; - - BoundBox bounds; - bool transform_applied; - bool transform_negative_scaled; - Transform transform_normal; - - PackedPatchTable *patch_table; - - uint motion_steps; - bool use_motion_blur; - - /* Update Flags */ - bool need_update; - bool need_update_rebuild; - - /* BVH */ - BVH *bvh; - size_t tri_offset; - size_t vert_offset; - - size_t curve_offset; - size_t curvekey_offset; - - size_t patch_offset; - size_t patch_table_offset; - size_t face_offset; - size_t corner_offset; - - size_t attr_map_offset; - - size_t num_subd_verts; - - /* Functions */ - Mesh(); - ~Mesh(); - - void resize_mesh(int numverts, int numfaces); - void reserve_mesh(int numverts, int numfaces); - void resize_curves(int numcurves, int numkeys); - void reserve_curves(int numcurves, int numkeys); - void resize_subd_faces(int numfaces, int num_ngons, int numcorners); - void reserve_subd_faces(int numfaces, int num_ngons, int numcorners); - void clear(bool preserve_voxel_data = false); - void add_vertex(float3 P); - void add_vertex_slow(float3 P); - void add_triangle(int v0, int v1, int v2, int shader, bool smooth); - void add_curve_key(float3 loc, float radius); - void add_curve(int first_key, int shader); - void add_subd_face(int* corners, int num_corners, int shader_, bool smooth_); - - void compute_bounds(); - void add_face_normals(); - void add_vertex_normals(); - void add_undisplaced(); - - void pack_shaders(Scene *scene, uint *shader); - void pack_normals(float4 *vnormal); - void pack_verts(const vector<uint>& tri_prim_index, - uint4 *tri_vindex, - uint *tri_patch, - float2 *tri_patch_uv, - size_t vert_offset, - size_t tri_offset); - void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); - void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset); - - void compute_bvh(Device *device, - DeviceScene *dscene, - SceneParams *params, - Progress *progress, - int n, - int total); - - bool need_attribute(Scene *scene, AttributeStandard std); - bool need_attribute(Scene *scene, ustring name); - - void tag_update(Scene *scene, bool rebuild); - - bool has_motion_blur() const; - bool has_true_displacement() const; - - /* Convert between normalized -1..1 motion time and index - * in the VERTEX_MOTION attribute. */ - float motion_time(int step) const; - int motion_step(float time) const; - - /* Check whether the mesh should have own BVH built separately. Briefly, - * own BVH is needed for mesh, if: - * - * - It is instanced multiple times, so each instance object should share the - * same BVH tree. - * - Special ray intersection is needed, for example to limit subsurface rays - * to only the mesh itself. - */ - bool need_build_bvh() const; - - /* Check if the mesh should be treated as instanced. */ - bool is_instanced() const; - - void tessellate(DiagSplit *split); + public: + NODE_DECLARE + + /* Mesh Triangle */ + struct Triangle { + int v[3]; + + void bounds_grow(const float3 *verts, BoundBox &bounds) const; + + void motion_verts(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + float time, + float3 r_verts[3]) const; + + void verts_for_step(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + size_t step, + float3 r_verts[3]) const; + + float3 compute_normal(const float3 *verts) const; + + bool valid(const float3 *verts) const; + }; + + Triangle get_triangle(size_t i) const + { + Triangle tri = {{triangles[i * 3 + 0], triangles[i * 3 + 1], triangles[i * 3 + 2]}}; + return tri; + } + + size_t num_triangles() const + { + return triangles.size() / 3; + } + + /* Mesh Curve */ + struct Curve { + int first_key; + int num_keys; + + int num_segments() + { + return num_keys - 1; + } + + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + BoundBox &bounds) const; + void bounds_grow(float4 keys[4], BoundBox &bounds) const; + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform &aligned_space, + BoundBox &bounds) const; + + void motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + float time, + size_t k0, + size_t k1, + float4 r_keys[2]) const; + void cardinal_motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + float time, + size_t k0, + size_t k1, + size_t k2, + size_t k3, + float4 r_keys[4]) const; + + void keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + float4 r_keys[2]) const; + void cardinal_keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + size_t k2, + size_t k3, + float4 r_keys[4]) const; + }; + + Curve get_curve(size_t i) const + { + int first = curve_first_key[i]; + int next_first = (i + 1 < curve_first_key.size()) ? curve_first_key[i + 1] : curve_keys.size(); + + Curve curve = {first, next_first - first}; + return curve; + } + + size_t num_curves() const + { + return curve_first_key.size(); + } + + /* Mesh SubdFace */ + struct SubdFace { + int start_corner; + int num_corners; + int shader; + bool smooth; + int ptex_offset; + + bool is_quad() + { + return num_corners == 4; + } + float3 normal(const Mesh *mesh) const; + int num_ptex_faces() const + { + return num_corners == 4 ? 1 : num_corners; + } + }; + + struct SubdEdgeCrease { + int v[2]; + float crease; + }; + + enum SubdivisionType { + SUBDIVISION_NONE, + SUBDIVISION_LINEAR, + SUBDIVISION_CATMULL_CLARK, + }; + + SubdivisionType subdivision_type; + + /* Mesh Data */ + enum GeometryFlags { + GEOMETRY_NONE = 0, + GEOMETRY_TRIANGLES = (1 << 0), + GEOMETRY_CURVES = (1 << 1), + }; + int geometry_flags; /* used to distinguish meshes with no verts + and meshed for which geometry is not created */ + + array<int> triangles; + array<float3> verts; + array<int> shader; + array<bool> smooth; + + /* used for storing patch info for subd triangles, only allocated if there are patches */ + array<int> triangle_patch; /* must be < 0 for non subd triangles */ + array<float2> vert_patch_uv; + + float volume_isovalue; + bool has_volume; /* Set in the device_update_flags(). */ + bool has_surface_bssrdf; /* Set in the device_update_flags(). */ + + array<float3> curve_keys; + array<float> curve_radius; + array<int> curve_first_key; + array<int> curve_shader; + + array<SubdFace> subd_faces; + array<int> subd_face_corners; + int num_ngons; + + array<SubdEdgeCrease> subd_creases; + + SubdParams *subd_params; + + vector<Shader *> used_shaders; + AttributeSet attributes; + AttributeSet curve_attributes; + AttributeSet subd_attributes; + + BoundBox bounds; + bool transform_applied; + bool transform_negative_scaled; + Transform transform_normal; + + PackedPatchTable *patch_table; + + uint motion_steps; + bool use_motion_blur; + + /* Update Flags */ + bool need_update; + bool need_update_rebuild; + + /* BVH */ + BVH *bvh; + size_t tri_offset; + size_t vert_offset; + + size_t curve_offset; + size_t curvekey_offset; + + size_t patch_offset; + size_t patch_table_offset; + size_t face_offset; + size_t corner_offset; + + size_t attr_map_offset; + + size_t num_subd_verts; + + /* Functions */ + Mesh(); + ~Mesh(); + + void resize_mesh(int numverts, int numfaces); + void reserve_mesh(int numverts, int numfaces); + void resize_curves(int numcurves, int numkeys); + void reserve_curves(int numcurves, int numkeys); + void resize_subd_faces(int numfaces, int num_ngons, int numcorners); + void reserve_subd_faces(int numfaces, int num_ngons, int numcorners); + void clear(bool preserve_voxel_data = false); + void add_vertex(float3 P); + void add_vertex_slow(float3 P); + void add_triangle(int v0, int v1, int v2, int shader, bool smooth); + void add_curve_key(float3 loc, float radius); + void add_curve(int first_key, int shader); + void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_); + + void compute_bounds(); + void add_face_normals(); + void add_vertex_normals(); + void add_undisplaced(); + + void pack_shaders(Scene *scene, uint *shader); + void pack_normals(float4 *vnormal); + void pack_verts(const vector<uint> &tri_prim_index, + uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv, + size_t vert_offset, + size_t tri_offset); + void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); + void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset); + + void compute_bvh(Device *device, + DeviceScene *dscene, + SceneParams *params, + Progress *progress, + int n, + int total); + + bool need_attribute(Scene *scene, AttributeStandard std); + bool need_attribute(Scene *scene, ustring name); + + void tag_update(Scene *scene, bool rebuild); + + bool has_motion_blur() const; + bool has_true_displacement() const; + + /* Convert between normalized -1..1 motion time and index + * in the VERTEX_MOTION attribute. */ + float motion_time(int step) const; + int motion_step(float time) const; + + /* Check whether the mesh should have own BVH built separately. Briefly, + * own BVH is needed for mesh, if: + * + * - It is instanced multiple times, so each instance object should share the + * same BVH tree. + * - Special ray intersection is needed, for example to limit subsurface rays + * to only the mesh itself. + */ + bool need_build_bvh() const; + + /* Check if the mesh should be treated as instanced. */ + bool is_instanced() const; + + void tessellate(DiagSplit *split); }; /* Mesh Manager */ class MeshManager { -public: - bool need_update; - bool need_flags_update; + public: + bool need_update; + bool need_flags_update; - MeshManager(); - ~MeshManager(); + MeshManager(); + ~MeshManager(); - bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress); + bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress); - /* attributes */ - void update_osl_attributes(Device *device, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); - void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); + /* attributes */ + void update_osl_attributes(Device *device, + Scene *scene, + vector<AttributeRequestSet> &mesh_attributes); + void update_svm_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + vector<AttributeRequestSet> &mesh_attributes); - void device_update_preprocess(Device *device, Scene *scene, Progress& progress); - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_update_preprocess(Device *device, 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); - void tag_update(Scene *scene); + void tag_update(Scene *scene); - void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); + void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); - void collect_statistics(const Scene *scene, RenderStats *stats); + void collect_statistics(const Scene *scene, RenderStats *stats); -protected: - /* Calculate verts/triangles/curves offsets in global arrays. */ - void mesh_calc_offset(Scene *scene); + protected: + /* Calculate verts/triangles/curves offsets in global arrays. */ + void mesh_calc_offset(Scene *scene); - void device_update_object(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress); + void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); - void device_update_mesh(Device *device, - DeviceScene *dscene, - Scene *scene, - bool for_displacement, - Progress& progress); + void device_update_mesh(Device *device, + DeviceScene *dscene, + Scene *scene, + bool for_displacement, + Progress &progress); - void device_update_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress); + void device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress); - void device_update_bvh(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress); + void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); - void device_update_displacement_images(Device *device, - Scene *scene, - Progress& progress); + void device_update_displacement_images(Device *device, Scene *scene, Progress &progress); - void device_update_volume_images(Device *device, - Scene *scene, - Progress& progress); + void device_update_volume_images(Device *device, Scene *scene, Progress &progress); }; CCL_NAMESPACE_END -#endif /* __MESH_H__ */ +#endif /* __MESH_H__ */ diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index 53b9bfa3451..5ae9348d83e 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -26,296 +26,301 @@ CCL_NAMESPACE_BEGIN -static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts) +static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts) { - float3 v0 = verts[t.v[0]]; - float3 v1 = verts[t.v[1]]; - float3 v2 = verts[t.v[2]]; + float3 v0 = verts[t.v[0]]; + float3 v1 = verts[t.v[1]]; + float3 v2 = verts[t.v[2]]; - float3 norm = cross(v1 - v0, v2 - v0); - float normlen = len(norm); + float3 norm = cross(v1 - v0, v2 - v0); + float normlen = len(norm); - if(normlen == 0.0f) - return make_float3(1.0f, 0.0f, 0.0f); + if (normlen == 0.0f) + return make_float3(1.0f, 0.0f, 0.0f); - return norm / normlen; + return norm / normlen; } -bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress) +bool MeshManager::displace( + Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress) { - /* verify if we have a displacement shader */ - if(!mesh->has_true_displacement()) { - return false; - } - - string msg = string_printf("Computing Displacement %s", mesh->name.c_str()); - progress.set_status("Updating Mesh", msg); - - /* find object index. todo: is arbitrary */ - size_t object_index = OBJECT_NONE; - - for(size_t i = 0; i < scene->objects.size(); i++) { - if(scene->objects[i]->mesh == mesh) { - object_index = i; - break; - } - } - - /* setup input for device task */ - const size_t num_verts = mesh->verts.size(); - vector<bool> done(num_verts, false); - device_vector<uint4> d_input(device, "displace_input", MEM_READ_ONLY); - uint4 *d_input_data = d_input.alloc(num_verts); - size_t d_input_size = 0; - - size_t num_triangles = mesh->num_triangles(); - for(size_t i = 0; i < num_triangles; i++) { - Mesh::Triangle t = mesh->get_triangle(i); - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) ? - mesh->used_shaders[shader_index] : scene->default_surface; - - if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { - continue; - } - - for(int j = 0; j < 3; j++) { - if(done[t.v[j]]) - continue; - - done[t.v[j]] = true; - - /* set up object, primitive and barycentric coordinates */ - int object = object_index; - int prim = mesh->tri_offset + i; - float u, v; - - switch(j) { - case 0: - u = 1.0f; - v = 0.0f; - break; - case 1: - u = 0.0f; - v = 1.0f; - break; - default: - u = 0.0f; - v = 0.0f; - break; - } - - /* back */ - uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v)); - d_input_data[d_input_size++] = in; - } - } - - if(d_input_size == 0) - return false; - - /* run device task */ - device_vector<float4> d_output(device, "displace_output", MEM_READ_WRITE); - d_output.alloc(d_input_size); - d_output.zero_to_device(); - d_input.copy_to_device(); - - /* needs to be up to data for attribute access */ - device->const_copy_to("__data", &dscene->data, sizeof(dscene->data)); - - DeviceTask task(DeviceTask::SHADER); - task.shader_input = d_input.device_pointer; - task.shader_output = d_output.device_pointer; - task.shader_eval_type = SHADER_EVAL_DISPLACE; - task.shader_x = 0; - task.shader_w = d_output.size(); - task.num_samples = 1; - task.get_cancel = function_bind(&Progress::get_cancel, &progress); - - device->task_add(task); - device->task_wait(); - - if(progress.get_cancel()) { - d_input.free(); - d_output.free(); - return false; - } - - d_output.copy_from_device(0, 1, d_output.size()); - d_input.free(); - - /* read result */ - done.clear(); - done.resize(num_verts, false); - int k = 0; - - float4 *offset = d_output.data(); - - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - for(size_t i = 0; i < num_triangles; i++) { - Mesh::Triangle t = mesh->get_triangle(i); - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) ? - mesh->used_shaders[shader_index] : scene->default_surface; - - if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { - continue; - } - - for(int j = 0; j < 3; j++) { - if(!done[t.v[j]]) { - done[t.v[j]] = true; - float3 off = float4_to_float3(offset[k++]); - /* Avoid illegal vertex coordinates. */ - off = ensure_finite3(off); - mesh->verts[t.v[j]] += off; - if(attr_mP != NULL) { - for(int step = 0; step < mesh->motion_steps - 1; step++) { - float3 *mP = attr_mP->data_float3() + step*num_verts; - mP[t.v[j]] += off; - } - } - } - } - } - - d_output.free(); - - /* for displacement method both, we only need to recompute the face - * normals, as bump mapping in the shader will already alter the - * vertex normal, so we start from the non-displaced vertex normals - * to avoid applying the perturbation twice. */ - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - mesh->add_face_normals(); - - bool need_recompute_vertex_normals = false; - - foreach(Shader *shader, mesh->used_shaders) { - if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) { - need_recompute_vertex_normals = true; - break; - } - } - - if(need_recompute_vertex_normals) { - bool flip = mesh->transform_negative_scaled; - vector<bool> tri_has_true_disp(num_triangles, false); - - for(size_t i = 0; i < num_triangles; i++) { - int shader_index = mesh->shader[i]; - Shader *shader = (shader_index < mesh->used_shaders.size()) ? - mesh->used_shaders[shader_index] : scene->default_surface; - - tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE; - } - - /* static vertex normals */ - - /* get attributes */ - Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL); - Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); - - float3 *fN = attr_fN->data_float3(); - float3 *vN = attr_vN->data_float3(); - - /* compute vertex normals */ - - /* zero vertex normals on triangles with true displacement */ - for(size_t i = 0; i < num_triangles; i++) { - if(tri_has_true_disp[i]) { - for(size_t j = 0; j < 3; j++) { - vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f); - } - } - } - - /* add face normals to vertex normals */ - for(size_t i = 0; i < num_triangles; i++) { - if(tri_has_true_disp[i]) { - for(size_t j = 0; j < 3; j++) { - vN[mesh->get_triangle(i).v[j]] += fN[i]; - } - } - } - - /* normalize vertex normals */ - done.clear(); - done.resize(num_verts, false); - - for(size_t i = 0; i < num_triangles; i++) { - if(tri_has_true_disp[i]) { - for(size_t j = 0; j < 3; j++) { - int vert = mesh->get_triangle(i).v[j]; - - if(done[vert]) { - continue; - } - - vN[vert] = normalize(vN[vert]); - if(flip) - vN[vert] = -vN[vert]; - - done[vert] = true; - } - } - } - - /* motion vertex normals */ - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - - if(mesh->has_motion_blur() && attr_mP && attr_mN) { - for(int step = 0; step < mesh->motion_steps - 1; step++) { - float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); - float3 *mN = attr_mN->data_float3() + step*mesh->verts.size(); - - /* compute */ - - /* zero vertex normals on triangles with true displacement */ - for(size_t i = 0; i < num_triangles; i++) { - if(tri_has_true_disp[i]) { - for(size_t j = 0; j < 3; j++) { - mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f); - } - } - } - - /* add face normals to vertex normals */ - for(size_t i = 0; i < num_triangles; i++) { - if(tri_has_true_disp[i]) { - for(size_t j = 0; j < 3; j++) { - float3 fN = compute_face_normal(mesh->get_triangle(i), mP); - mN[mesh->get_triangle(i).v[j]] += fN; - } - } - } - - /* normalize vertex normals */ - done.clear(); - done.resize(num_verts, false); - - for(size_t i = 0; i < num_triangles; i++) { - if(tri_has_true_disp[i]) { - for(size_t j = 0; j < 3; j++) { - int vert = mesh->get_triangle(i).v[j]; - - if(done[vert]) { - continue; - } - - mN[vert] = normalize(mN[vert]); - if(flip) - mN[vert] = -mN[vert]; - - done[vert] = true; - } - } - } - } - } - } - - return true; + /* verify if we have a displacement shader */ + if (!mesh->has_true_displacement()) { + return false; + } + + string msg = string_printf("Computing Displacement %s", mesh->name.c_str()); + progress.set_status("Updating Mesh", msg); + + /* find object index. todo: is arbitrary */ + size_t object_index = OBJECT_NONE; + + for (size_t i = 0; i < scene->objects.size(); i++) { + if (scene->objects[i]->mesh == mesh) { + object_index = i; + break; + } + } + + /* setup input for device task */ + const size_t num_verts = mesh->verts.size(); + vector<bool> done(num_verts, false); + device_vector<uint4> d_input(device, "displace_input", MEM_READ_ONLY); + uint4 *d_input_data = d_input.alloc(num_verts); + size_t d_input_size = 0; + + size_t num_triangles = mesh->num_triangles(); + for (size_t i = 0; i < num_triangles; i++) { + Mesh::Triangle t = mesh->get_triangle(i); + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) ? + mesh->used_shaders[shader_index] : + scene->default_surface; + + if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { + continue; + } + + for (int j = 0; j < 3; j++) { + if (done[t.v[j]]) + continue; + + done[t.v[j]] = true; + + /* set up object, primitive and barycentric coordinates */ + int object = object_index; + int prim = mesh->tri_offset + i; + float u, v; + + switch (j) { + case 0: + u = 1.0f; + v = 0.0f; + break; + case 1: + u = 0.0f; + v = 1.0f; + break; + default: + u = 0.0f; + v = 0.0f; + break; + } + + /* back */ + uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v)); + d_input_data[d_input_size++] = in; + } + } + + if (d_input_size == 0) + return false; + + /* run device task */ + device_vector<float4> d_output(device, "displace_output", MEM_READ_WRITE); + d_output.alloc(d_input_size); + d_output.zero_to_device(); + d_input.copy_to_device(); + + /* needs to be up to data for attribute access */ + device->const_copy_to("__data", &dscene->data, sizeof(dscene->data)); + + DeviceTask task(DeviceTask::SHADER); + task.shader_input = d_input.device_pointer; + task.shader_output = d_output.device_pointer; + task.shader_eval_type = SHADER_EVAL_DISPLACE; + task.shader_x = 0; + task.shader_w = d_output.size(); + task.num_samples = 1; + task.get_cancel = function_bind(&Progress::get_cancel, &progress); + + device->task_add(task); + device->task_wait(); + + if (progress.get_cancel()) { + d_input.free(); + d_output.free(); + return false; + } + + d_output.copy_from_device(0, 1, d_output.size()); + d_input.free(); + + /* read result */ + done.clear(); + done.resize(num_verts, false); + int k = 0; + + float4 *offset = d_output.data(); + + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + for (size_t i = 0; i < num_triangles; i++) { + Mesh::Triangle t = mesh->get_triangle(i); + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) ? + mesh->used_shaders[shader_index] : + scene->default_surface; + + if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { + continue; + } + + for (int j = 0; j < 3; j++) { + if (!done[t.v[j]]) { + done[t.v[j]] = true; + float3 off = float4_to_float3(offset[k++]); + /* Avoid illegal vertex coordinates. */ + off = ensure_finite3(off); + mesh->verts[t.v[j]] += off; + if (attr_mP != NULL) { + for (int step = 0; step < mesh->motion_steps - 1; step++) { + float3 *mP = attr_mP->data_float3() + step * num_verts; + mP[t.v[j]] += off; + } + } + } + } + } + + d_output.free(); + + /* for displacement method both, we only need to recompute the face + * normals, as bump mapping in the shader will already alter the + * vertex normal, so we start from the non-displaced vertex normals + * to avoid applying the perturbation twice. */ + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + + bool need_recompute_vertex_normals = false; + + foreach (Shader *shader, mesh->used_shaders) { + if (shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) { + need_recompute_vertex_normals = true; + break; + } + } + + if (need_recompute_vertex_normals) { + bool flip = mesh->transform_negative_scaled; + vector<bool> tri_has_true_disp(num_triangles, false); + + for (size_t i = 0; i < num_triangles; i++) { + int shader_index = mesh->shader[i]; + Shader *shader = (shader_index < mesh->used_shaders.size()) ? + mesh->used_shaders[shader_index] : + scene->default_surface; + + tri_has_true_disp[i] = shader->has_displacement && + shader->displacement_method == DISPLACE_TRUE; + } + + /* static vertex normals */ + + /* get attributes */ + Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL); + Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + + float3 *fN = attr_fN->data_float3(); + float3 *vN = attr_vN->data_float3(); + + /* compute vertex normals */ + + /* zero vertex normals on triangles with true displacement */ + for (size_t i = 0; i < num_triangles; i++) { + if (tri_has_true_disp[i]) { + for (size_t j = 0; j < 3; j++) { + vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f); + } + } + } + + /* add face normals to vertex normals */ + for (size_t i = 0; i < num_triangles; i++) { + if (tri_has_true_disp[i]) { + for (size_t j = 0; j < 3; j++) { + vN[mesh->get_triangle(i).v[j]] += fN[i]; + } + } + } + + /* normalize vertex normals */ + done.clear(); + done.resize(num_verts, false); + + for (size_t i = 0; i < num_triangles; i++) { + if (tri_has_true_disp[i]) { + for (size_t j = 0; j < 3; j++) { + int vert = mesh->get_triangle(i).v[j]; + + if (done[vert]) { + continue; + } + + vN[vert] = normalize(vN[vert]); + if (flip) + vN[vert] = -vN[vert]; + + done[vert] = true; + } + } + } + + /* motion vertex normals */ + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + + if (mesh->has_motion_blur() && attr_mP && attr_mN) { + for (int step = 0; step < mesh->motion_steps - 1; step++) { + float3 *mP = attr_mP->data_float3() + step * mesh->verts.size(); + float3 *mN = attr_mN->data_float3() + step * mesh->verts.size(); + + /* compute */ + + /* zero vertex normals on triangles with true displacement */ + for (size_t i = 0; i < num_triangles; i++) { + if (tri_has_true_disp[i]) { + for (size_t j = 0; j < 3; j++) { + mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f); + } + } + } + + /* add face normals to vertex normals */ + for (size_t i = 0; i < num_triangles; i++) { + if (tri_has_true_disp[i]) { + for (size_t j = 0; j < 3; j++) { + float3 fN = compute_face_normal(mesh->get_triangle(i), mP); + mN[mesh->get_triangle(i).v[j]] += fN; + } + } + } + + /* normalize vertex normals */ + done.clear(); + done.resize(num_verts, false); + + for (size_t i = 0; i < num_triangles; i++) { + if (tri_has_true_disp[i]) { + for (size_t j = 0; j < 3; j++) { + int vert = mesh->get_triangle(i).v[j]; + + if (done[vert]) { + continue; + } + + mN[vert] = normalize(mN[vert]); + if (flip) + mN[vert] = -mN[vert]; + + done[vert] = true; + } + } + } + } + } + } + + return true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp index 95cc6f1fca1..46c8240fb71 100644 --- a/intern/cycles/render/mesh_subdivision.cpp +++ b/intern/cycles/render/mesh_subdivision.cpp @@ -31,87 +31,92 @@ CCL_NAMESPACE_BEGIN CCL_NAMESPACE_END -#include <opensubdiv/far/topologyRefinerFactory.h> -#include <opensubdiv/far/primvarRefiner.h> -#include <opensubdiv/far/patchTableFactory.h> -#include <opensubdiv/far/patchMap.h> +# include <opensubdiv/far/topologyRefinerFactory.h> +# include <opensubdiv/far/primvarRefiner.h> +# include <opensubdiv/far/patchTableFactory.h> +# include <opensubdiv/far/patchMap.h> /* specializations of TopologyRefinerFactory for ccl::Mesh */ namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Far { - template<> - bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh) - { - setNumBaseVertices(refiner, mesh.verts.size()); - setNumBaseFaces(refiner, mesh.subd_faces.size()); +template<> +bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner &refiner, + ccl::Mesh const &mesh) +{ + setNumBaseVertices(refiner, mesh.verts.size()); + setNumBaseFaces(refiner, mesh.subd_faces.size()); - const ccl::Mesh::SubdFace* face = mesh.subd_faces.data(); + const ccl::Mesh::SubdFace *face = mesh.subd_faces.data(); - for(int i = 0; i < mesh.subd_faces.size(); i++, face++) { - setNumBaseFaceVertices(refiner, i, face->num_corners); - } + for (int i = 0; i < mesh.subd_faces.size(); i++, face++) { + setNumBaseFaceVertices(refiner, i, face->num_corners); + } - return true; - } + return true; +} - template<> - bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh) - { - const ccl::Mesh::SubdFace* face = mesh.subd_faces.data(); +template<> +bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner &refiner, + ccl::Mesh const &mesh) +{ + const ccl::Mesh::SubdFace *face = mesh.subd_faces.data(); - for(int i = 0; i < mesh.subd_faces.size(); i++, face++) { - IndexArray face_verts = getBaseFaceVertices(refiner, i); + for (int i = 0; i < mesh.subd_faces.size(); i++, face++) { + IndexArray face_verts = getBaseFaceVertices(refiner, i); - int* corner = &mesh.subd_face_corners[face->start_corner]; + int *corner = &mesh.subd_face_corners[face->start_corner]; - for(int j = 0; j < face->num_corners; j++, corner++) { - face_verts[j] = *corner; - } - } + for (int j = 0; j < face->num_corners; j++, corner++) { + face_verts[j] = *corner; + } + } - return true; - } + return true; +} - template<> - bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner& refiner, ccl::Mesh const& mesh) - { - const ccl::Mesh::SubdEdgeCrease* crease = mesh.subd_creases.data(); +template<> +bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner &refiner, + ccl::Mesh const &mesh) +{ + const ccl::Mesh::SubdEdgeCrease *crease = mesh.subd_creases.data(); - for(int i = 0; i < mesh.subd_creases.size(); i++, crease++) { - Index edge = findBaseEdge(refiner, crease->v[0], crease->v[1]); + for (int i = 0; i < mesh.subd_creases.size(); i++, crease++) { + Index edge = findBaseEdge(refiner, crease->v[0], crease->v[1]); - if(edge != INDEX_INVALID) { - setBaseEdgeSharpness(refiner, edge, crease->crease * 10.0f); - } - } + if (edge != INDEX_INVALID) { + setBaseEdgeSharpness(refiner, edge, crease->crease * 10.0f); + } + } - for(int i = 0; i < mesh.verts.size(); i++) { - ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i); + for (int i = 0; i < mesh.verts.size(); i++) { + ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i); - if(vert_edges.size() == 2) { - float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]); - sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); + if (vert_edges.size() == 2) { + float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]); + sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); - setBaseVertexSharpness(refiner, i, sharpness); - } - } + setBaseVertexSharpness(refiner, i, sharpness); + } + } - return true; - } + return true; +} - template<> - bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner& /*refiner*/, ccl::Mesh const& /*mesh*/) - { - return true; - } +template<> +bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner & /*refiner*/, + ccl::Mesh const & /*mesh*/) +{ + return true; +} - template<> - void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/, - char const * /*msg*/, ccl::Mesh const& /*mesh*/) - { - } +template<> +void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/, + char const * /*msg*/, + ccl::Mesh const & /*mesh*/) +{ +} } /* namespace Far */ } /* namespace OPENSUBDIV_VERSION */ } /* namespace OpenSubdiv */ @@ -122,226 +127,242 @@ using namespace OpenSubdiv; /* struct that implements OpenSubdiv's vertex interface */ -template<typename T> -struct OsdValue { - T value; +template<typename T> struct OsdValue { + T value; - OsdValue() {} + OsdValue() + { + } - void Clear(void* = 0) { - memset(&value, 0, sizeof(T)); - } + void Clear(void * = 0) + { + memset(&value, 0, sizeof(T)); + } - void AddWithWeight(OsdValue<T> const& src, float weight) { - value += src.value * weight; - } + void AddWithWeight(OsdValue<T> const &src, float weight) + { + value += src.value * weight; + } }; -template<> -void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const& src, float weight) +template<> void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const &src, float weight) { - for(int i = 0; i < 4; i++) { - value[i] += (uchar)(src.value[i] * weight); - } + for (int i = 0; i < 4; i++) { + value[i] += (uchar)(src.value[i] * weight); + } } /* class for holding OpenSubdiv data used during tessellation */ class OsdData { - Mesh* mesh; - vector<OsdValue<float3> > verts; - Far::TopologyRefiner* refiner; - Far::PatchTable* patch_table; - Far::PatchMap* patch_map; - -public: - OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL) {} - - ~OsdData() - { - delete refiner; - delete patch_table; - delete patch_map; - } - - void build_from_mesh(Mesh* mesh_) - { - mesh = mesh_; - - /* type and options */ - Sdc::SchemeType type = Sdc::SCHEME_CATMARK; - - Sdc::Options options; - options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY); - - /* create refiner */ - refiner = Far::TopologyRefinerFactory<Mesh>::Create(*mesh, - Far::TopologyRefinerFactory<Mesh>::Options(type, options)); - - /* adaptive refinement */ - int max_isolation = calculate_max_isolation(); - refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation)); - - /* create patch table */ - Far::PatchTableFactory::Options patch_options; - patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS; - - patch_table = Far::PatchTableFactory::Create(*refiner, patch_options); - - /* interpolate verts */ - int num_refiner_verts = refiner->GetNumVerticesTotal(); - int num_local_points = patch_table->GetNumLocalPoints(); - - verts.resize(num_refiner_verts + num_local_points); - for(int i = 0; i < mesh->verts.size(); i++) { - verts[i].value = mesh->verts[i]; - } - - OsdValue<float3>* src = verts.data(); - for(int i = 0; i < refiner->GetMaxLevel(); i++) { - OsdValue<float3>* dest = src + refiner->GetLevel(i).GetNumVertices(); - Far::PrimvarRefiner(*refiner).Interpolate(i+1, src, dest); - src = dest; - } - - if(num_local_points) { - patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]); - } - - /* create patch map */ - patch_map = new Far::PatchMap(*patch_table); - } - - void subdivide_attribute(Attribute& attr) - { - Far::PrimvarRefiner primvar_refiner(*refiner); - - if(attr.element == ATTR_ELEMENT_VERTEX) { - int num_refiner_verts = refiner->GetNumVerticesTotal(); - int num_local_points = patch_table->GetNumLocalPoints(); - - attr.resize(num_refiner_verts + num_local_points); - attr.flags |= ATTR_FINAL_SIZE; - - char* src = attr.buffer.data(); - - for(int i = 0; i < refiner->GetMaxLevel(); i++) { - char* dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof(); - - if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) { - primvar_refiner.Interpolate(i+1, (OsdValue<float>*)src, (OsdValue<float>*&)dest); - } - else if(attr.same_storage(attr.type, TypeFloat2)) { - primvar_refiner.Interpolate(i+1, (OsdValue<float2>*)src, (OsdValue<float2>*&)dest); - } - else { - primvar_refiner.Interpolate(i+1, (OsdValue<float4>*)src, (OsdValue<float4>*&)dest); - } - - src = dest; - } - - if(num_local_points) { - if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) { - patch_table->ComputeLocalPointValues((OsdValue<float>*)&attr.buffer[0], - (OsdValue<float>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]); - } - else if(attr.same_storage(attr.type, TypeFloat2)) { - patch_table->ComputeLocalPointValues((OsdValue<float2>*)&attr.buffer[0], - (OsdValue<float2>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]); - } - else { - patch_table->ComputeLocalPointValues((OsdValue<float4>*)&attr.buffer[0], - (OsdValue<float4>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]); - } - } - } - else if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) { - // TODO(mai): fvar interpolation - } - } - - int calculate_max_isolation() - { - /* loop over all edges to find longest in screen space */ - const Far::TopologyLevel& level = refiner->GetLevel(0); - Transform objecttoworld = mesh->subd_params->objecttoworld; - Camera* cam = mesh->subd_params->camera; - - float longest_edge = 0.0f; - - for(size_t i = 0; i < level.GetNumEdges(); i++) { - Far::ConstIndexArray verts = level.GetEdgeVertices(i); - - float3 a = mesh->verts[verts[0]]; - float3 b = mesh->verts[verts[1]]; - - float edge_len; - - if(cam) { - a = transform_point(&objecttoworld, a); - b = transform_point(&objecttoworld, b); - - edge_len = len(a - b) / cam->world_to_raster_size((a + b) * 0.5f); - } - else { - edge_len = len(a - b); - } - - longest_edge = max(longest_edge, edge_len); - } - - /* calculate isolation level */ - int isolation = (int)(log2f(max(longest_edge / mesh->subd_params->dicing_rate, 1.0f)) + 1.0f); - - return min(isolation, 10); - } - - friend struct OsdPatch; - friend class Mesh; + Mesh *mesh; + vector<OsdValue<float3>> verts; + Far::TopologyRefiner *refiner; + Far::PatchTable *patch_table; + Far::PatchMap *patch_map; + + public: + OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL) + { + } + + ~OsdData() + { + delete refiner; + delete patch_table; + delete patch_map; + } + + void build_from_mesh(Mesh *mesh_) + { + mesh = mesh_; + + /* type and options */ + Sdc::SchemeType type = Sdc::SCHEME_CATMARK; + + Sdc::Options options; + options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY); + + /* create refiner */ + refiner = Far::TopologyRefinerFactory<Mesh>::Create( + *mesh, Far::TopologyRefinerFactory<Mesh>::Options(type, options)); + + /* adaptive refinement */ + int max_isolation = calculate_max_isolation(); + refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation)); + + /* create patch table */ + Far::PatchTableFactory::Options patch_options; + patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS; + + patch_table = Far::PatchTableFactory::Create(*refiner, patch_options); + + /* interpolate verts */ + int num_refiner_verts = refiner->GetNumVerticesTotal(); + int num_local_points = patch_table->GetNumLocalPoints(); + + verts.resize(num_refiner_verts + num_local_points); + for (int i = 0; i < mesh->verts.size(); i++) { + verts[i].value = mesh->verts[i]; + } + + OsdValue<float3> *src = verts.data(); + for (int i = 0; i < refiner->GetMaxLevel(); i++) { + OsdValue<float3> *dest = src + refiner->GetLevel(i).GetNumVertices(); + Far::PrimvarRefiner(*refiner).Interpolate(i + 1, src, dest); + src = dest; + } + + if (num_local_points) { + patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]); + } + + /* create patch map */ + patch_map = new Far::PatchMap(*patch_table); + } + + void subdivide_attribute(Attribute &attr) + { + Far::PrimvarRefiner primvar_refiner(*refiner); + + if (attr.element == ATTR_ELEMENT_VERTEX) { + int num_refiner_verts = refiner->GetNumVerticesTotal(); + int num_local_points = patch_table->GetNumLocalPoints(); + + attr.resize(num_refiner_verts + num_local_points); + attr.flags |= ATTR_FINAL_SIZE; + + char *src = attr.buffer.data(); + + for (int i = 0; i < refiner->GetMaxLevel(); i++) { + char *dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof(); + + if (attr.same_storage(attr.type, TypeDesc::TypeFloat)) { + primvar_refiner.Interpolate(i + 1, (OsdValue<float> *)src, (OsdValue<float> *&)dest); + } + else if (attr.same_storage(attr.type, TypeFloat2)) { + primvar_refiner.Interpolate(i + 1, (OsdValue<float2> *)src, (OsdValue<float2> *&)dest); + } + else { + primvar_refiner.Interpolate(i + 1, (OsdValue<float4> *)src, (OsdValue<float4> *&)dest); + } + + src = dest; + } + + if (num_local_points) { + if (attr.same_storage(attr.type, TypeDesc::TypeFloat)) { + patch_table->ComputeLocalPointValues( + (OsdValue<float> *)&attr.buffer[0], + (OsdValue<float> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]); + } + else if (attr.same_storage(attr.type, TypeFloat2)) { + patch_table->ComputeLocalPointValues( + (OsdValue<float2> *)&attr.buffer[0], + (OsdValue<float2> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]); + } + else { + patch_table->ComputeLocalPointValues( + (OsdValue<float4> *)&attr.buffer[0], + (OsdValue<float4> *)&attr.buffer[num_refiner_verts * attr.data_sizeof()]); + } + } + } + else if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) { + // TODO(mai): fvar interpolation + } + } + + int calculate_max_isolation() + { + /* loop over all edges to find longest in screen space */ + const Far::TopologyLevel &level = refiner->GetLevel(0); + Transform objecttoworld = mesh->subd_params->objecttoworld; + Camera *cam = mesh->subd_params->camera; + + float longest_edge = 0.0f; + + for (size_t i = 0; i < level.GetNumEdges(); i++) { + Far::ConstIndexArray verts = level.GetEdgeVertices(i); + + float3 a = mesh->verts[verts[0]]; + float3 b = mesh->verts[verts[1]]; + + float edge_len; + + if (cam) { + a = transform_point(&objecttoworld, a); + b = transform_point(&objecttoworld, b); + + edge_len = len(a - b) / cam->world_to_raster_size((a + b) * 0.5f); + } + else { + edge_len = len(a - b); + } + + longest_edge = max(longest_edge, edge_len); + } + + /* calculate isolation level */ + int isolation = (int)(log2f(max(longest_edge / mesh->subd_params->dicing_rate, 1.0f)) + 1.0f); + + return min(isolation, 10); + } + + friend struct OsdPatch; + friend class Mesh; }; /* ccl::Patch implementation that uses OpenSubdiv for eval */ struct OsdPatch : Patch { - OsdData* osd_data; - - OsdPatch(OsdData* data) : osd_data(data) {} - - void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) - { - const Far::PatchTable::PatchHandle* handle = osd_data->patch_map->FindPatch(patch_index, u, v); - assert(handle); - - float p_weights[20], du_weights[20], dv_weights[20]; - osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights); - - Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle); - - float3 du, dv; - if(P) *P = make_float3(0.0f, 0.0f, 0.0f); - du = make_float3(0.0f, 0.0f, 0.0f); - dv = make_float3(0.0f, 0.0f, 0.0f); - - for(int i = 0; i < cv.size(); i++) { - float3 p = osd_data->verts[cv[i]].value; - - if(P) *P += p * p_weights[i]; - du += p * du_weights[i]; - dv += p * dv_weights[i]; - } - - if(dPdu) *dPdu = du; - if(dPdv) *dPdv = dv; - if(N) { - *N = cross(du, dv); - - float t = len(*N); - *N = (t != 0.0f) ? *N/t : make_float3(0.0f, 0.0f, 1.0f); - } - } - - BoundBox bound() { return BoundBox::empty; } + OsdData *osd_data; + + OsdPatch(OsdData *data) : osd_data(data) + { + } + + void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) + { + const Far::PatchTable::PatchHandle *handle = osd_data->patch_map->FindPatch(patch_index, u, v); + assert(handle); + + float p_weights[20], du_weights[20], dv_weights[20]; + osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights); + + Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle); + + float3 du, dv; + if (P) + *P = make_float3(0.0f, 0.0f, 0.0f); + du = make_float3(0.0f, 0.0f, 0.0f); + dv = make_float3(0.0f, 0.0f, 0.0f); + + for (int i = 0; i < cv.size(); i++) { + float3 p = osd_data->verts[cv[i]].value; + + if (P) + *P += p * p_weights[i]; + du += p * du_weights[i]; + dv += p * dv_weights[i]; + } + + if (dPdu) + *dPdu = du; + if (dPdv) + *dPdv = dv; + if (N) { + *N = cross(du, dv); + + float t = len(*N); + *N = (t != 0.0f) ? *N / t : make_float3(0.0f, 0.0f, 1.0f); + } + } + + BoundBox bound() + { + return BoundBox::empty; + } }; #endif @@ -349,273 +370,280 @@ struct OsdPatch : Patch { void Mesh::tessellate(DiagSplit *split) { #ifdef WITH_OPENSUBDIV - OsdData osd_data; - bool need_packed_patch_table = false; - - if(subdivision_type == SUBDIVISION_CATMULL_CLARK) { - if(subd_faces.size()) { - osd_data.build_from_mesh(this); - } - } - else + OsdData osd_data; + bool need_packed_patch_table = false; + + if (subdivision_type == SUBDIVISION_CATMULL_CLARK) { + if (subd_faces.size()) { + osd_data.build_from_mesh(this); + } + } + else #endif - { - /* force linear subdivision if OpenSubdiv is unavailable to avoid - * falling into catmull-clark code paths by accident - */ - subdivision_type = SUBDIVISION_LINEAR; + { + /* force linear subdivision if OpenSubdiv is unavailable to avoid + * falling into catmull-clark code paths by accident + */ + subdivision_type = SUBDIVISION_LINEAR; - /* force disable attribute subdivision for same reason as above */ - foreach(Attribute& attr, subd_attributes.attributes) { - attr.flags &= ~ATTR_SUBDIVIDED; - } - } + /* force disable attribute subdivision for same reason as above */ + foreach (Attribute &attr, subd_attributes.attributes) { + attr.flags &= ~ATTR_SUBDIVIDED; + } + } - int num_faces = subd_faces.size(); + int num_faces = subd_faces.size(); - Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL); - float3* vN = attr_vN->data_float3(); + Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL); + float3 *vN = attr_vN->data_float3(); - for(int f = 0; f < num_faces; f++) { - SubdFace& face = subd_faces[f]; + for (int f = 0; f < num_faces; f++) { + SubdFace &face = subd_faces[f]; - if(face.is_quad()) { - /* quad */ - QuadDice::SubPatch subpatch; + if (face.is_quad()) { + /* quad */ + QuadDice::SubPatch subpatch; - LinearQuadPatch quad_patch; + LinearQuadPatch quad_patch; #ifdef WITH_OPENSUBDIV - OsdPatch osd_patch(&osd_data); + OsdPatch osd_patch(&osd_data); - if(subdivision_type == SUBDIVISION_CATMULL_CLARK) { - osd_patch.patch_index = face.ptex_offset; + if (subdivision_type == SUBDIVISION_CATMULL_CLARK) { + osd_patch.patch_index = face.ptex_offset; - subpatch.patch = &osd_patch; - } - else + subpatch.patch = &osd_patch; + } + else #endif - { - float3 *hull = quad_patch.hull; - float3 *normals = quad_patch.normals; - - quad_patch.patch_index = face.ptex_offset; - - for(int i = 0; i < 4; i++) { - hull[i] = verts[subd_face_corners[face.start_corner+i]]; - } - - if(face.smooth) { - for(int i = 0; i < 4; i++) { - normals[i] = vN[subd_face_corners[face.start_corner+i]]; - } - } - else { - float3 N = face.normal(this); - for(int i = 0; i < 4; i++) { - normals[i] = N; - } - } - - swap(hull[2], hull[3]); - swap(normals[2], normals[3]); - - subpatch.patch = &quad_patch; - } - - subpatch.patch->shader = face.shader; - - /* Quad faces need to be split at least once to line up with split ngons, we do this - * here in this manner because if we do it later edge factors may end up slightly off. - */ - subpatch.P00 = make_float2(0.0f, 0.0f); - subpatch.P10 = make_float2(0.5f, 0.0f); - subpatch.P01 = make_float2(0.0f, 0.5f); - subpatch.P11 = make_float2(0.5f, 0.5f); - split->split_quad(subpatch.patch, &subpatch); - - subpatch.P00 = make_float2(0.5f, 0.0f); - subpatch.P10 = make_float2(1.0f, 0.0f); - subpatch.P01 = make_float2(0.5f, 0.5f); - subpatch.P11 = make_float2(1.0f, 0.5f); - split->split_quad(subpatch.patch, &subpatch); - - subpatch.P00 = make_float2(0.0f, 0.5f); - subpatch.P10 = make_float2(0.5f, 0.5f); - subpatch.P01 = make_float2(0.0f, 1.0f); - subpatch.P11 = make_float2(0.5f, 1.0f); - split->split_quad(subpatch.patch, &subpatch); - - subpatch.P00 = make_float2(0.5f, 0.5f); - subpatch.P10 = make_float2(1.0f, 0.5f); - subpatch.P01 = make_float2(0.5f, 1.0f); - subpatch.P11 = make_float2(1.0f, 1.0f); - split->split_quad(subpatch.patch, &subpatch); - } - else { - /* ngon */ + { + float3 *hull = quad_patch.hull; + float3 *normals = quad_patch.normals; + + quad_patch.patch_index = face.ptex_offset; + + for (int i = 0; i < 4; i++) { + hull[i] = verts[subd_face_corners[face.start_corner + i]]; + } + + if (face.smooth) { + for (int i = 0; i < 4; i++) { + normals[i] = vN[subd_face_corners[face.start_corner + i]]; + } + } + else { + float3 N = face.normal(this); + for (int i = 0; i < 4; i++) { + normals[i] = N; + } + } + + swap(hull[2], hull[3]); + swap(normals[2], normals[3]); + + subpatch.patch = &quad_patch; + } + + subpatch.patch->shader = face.shader; + + /* Quad faces need to be split at least once to line up with split ngons, we do this + * here in this manner because if we do it later edge factors may end up slightly off. + */ + subpatch.P00 = make_float2(0.0f, 0.0f); + subpatch.P10 = make_float2(0.5f, 0.0f); + subpatch.P01 = make_float2(0.0f, 0.5f); + subpatch.P11 = make_float2(0.5f, 0.5f); + split->split_quad(subpatch.patch, &subpatch); + + subpatch.P00 = make_float2(0.5f, 0.0f); + subpatch.P10 = make_float2(1.0f, 0.0f); + subpatch.P01 = make_float2(0.5f, 0.5f); + subpatch.P11 = make_float2(1.0f, 0.5f); + split->split_quad(subpatch.patch, &subpatch); + + subpatch.P00 = make_float2(0.0f, 0.5f); + subpatch.P10 = make_float2(0.5f, 0.5f); + subpatch.P01 = make_float2(0.0f, 1.0f); + subpatch.P11 = make_float2(0.5f, 1.0f); + split->split_quad(subpatch.patch, &subpatch); + + subpatch.P00 = make_float2(0.5f, 0.5f); + subpatch.P10 = make_float2(1.0f, 0.5f); + subpatch.P01 = make_float2(0.5f, 1.0f); + subpatch.P11 = make_float2(1.0f, 1.0f); + split->split_quad(subpatch.patch, &subpatch); + } + else { + /* ngon */ #ifdef WITH_OPENSUBDIV - if(subdivision_type == SUBDIVISION_CATMULL_CLARK) { - OsdPatch patch(&osd_data); + if (subdivision_type == SUBDIVISION_CATMULL_CLARK) { + OsdPatch patch(&osd_data); - patch.shader = face.shader; + patch.shader = face.shader; - for(int corner = 0; corner < face.num_corners; corner++) { - patch.patch_index = face.ptex_offset + corner; + for (int corner = 0; corner < face.num_corners; corner++) { + patch.patch_index = face.ptex_offset + corner; - split->split_quad(&patch); - } - } - else + split->split_quad(&patch); + } + } + else #endif - { - float3 center_vert = make_float3(0.0f, 0.0f, 0.0f); - float3 center_normal = make_float3(0.0f, 0.0f, 0.0f); - - float inv_num_corners = 1.0f/float(face.num_corners); - for(int corner = 0; corner < face.num_corners; corner++) { - center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners; - center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners; - } - - for(int corner = 0; corner < face.num_corners; corner++) { - LinearQuadPatch patch; - float3 *hull = patch.hull; - float3 *normals = patch.normals; - - patch.patch_index = face.ptex_offset + corner; - - patch.shader = face.shader; - - hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; - hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; - hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; - hull[3] = center_vert; - - hull[1] = (hull[1] + hull[0]) * 0.5; - hull[2] = (hull[2] + hull[0]) * 0.5; - - if(face.smooth) { - normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; - normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; - normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; - normals[3] = center_normal; - - normals[1] = (normals[1] + normals[0]) * 0.5; - normals[2] = (normals[2] + normals[0]) * 0.5; - } - else { - float3 N = face.normal(this); - for(int i = 0; i < 4; i++) { - normals[i] = N; - } - } - - split->split_quad(&patch); - } - } - } - } - - /* interpolate center points for attributes */ - foreach(Attribute& attr, subd_attributes.attributes) { + { + float3 center_vert = make_float3(0.0f, 0.0f, 0.0f); + float3 center_normal = make_float3(0.0f, 0.0f, 0.0f); + + float inv_num_corners = 1.0f / float(face.num_corners); + for (int corner = 0; corner < face.num_corners; corner++) { + center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners; + center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners; + } + + for (int corner = 0; corner < face.num_corners; corner++) { + LinearQuadPatch patch; + float3 *hull = patch.hull; + float3 *normals = patch.normals; + + patch.patch_index = face.ptex_offset + corner; + + patch.shader = face.shader; + + hull[0] = + verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; + hull[1] = + verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; + hull[2] = + verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; + hull[3] = center_vert; + + hull[1] = (hull[1] + hull[0]) * 0.5; + hull[2] = (hull[2] + hull[0]) * 0.5; + + if (face.smooth) { + normals[0] = + vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]]; + normals[1] = + vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]]; + normals[2] = + vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]]; + normals[3] = center_normal; + + normals[1] = (normals[1] + normals[0]) * 0.5; + normals[2] = (normals[2] + normals[0]) * 0.5; + } + else { + float3 N = face.normal(this); + for (int i = 0; i < 4; i++) { + normals[i] = N; + } + } + + split->split_quad(&patch); + } + } + } + } + + /* interpolate center points for attributes */ + foreach (Attribute &attr, subd_attributes.attributes) { #ifdef WITH_OPENSUBDIV - if(subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) { - if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) { - /* keep subdivision for corner attributes disabled for now */ - attr.flags &= ~ATTR_SUBDIVIDED; - } - else if(subd_faces.size()) { - osd_data.subdivide_attribute(attr); - - need_packed_patch_table = true; - continue; - } - } + if (subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) { + if (attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) { + /* keep subdivision for corner attributes disabled for now */ + attr.flags &= ~ATTR_SUBDIVIDED; + } + else if (subd_faces.size()) { + osd_data.subdivide_attribute(attr); + + need_packed_patch_table = true; + continue; + } + } #endif - char* data = attr.data(); - size_t stride = attr.data_sizeof(); - int ngons = 0; - - switch(attr.element) { - case ATTR_ELEMENT_VERTEX: { - for(int f = 0; f < num_faces; f++) { - SubdFace& face = subd_faces[f]; - - if(!face.is_quad()) { - char* center = data + (verts.size() - num_subd_verts + ngons) * stride; - attr.zero_data(center); - - float inv_num_corners = 1.0f / float(face.num_corners); - - for(int corner = 0; corner < face.num_corners; corner++) { - attr.add_with_weight(center, - data + subd_face_corners[face.start_corner + corner] * stride, - inv_num_corners); - } - - ngons++; - } - } - } break; - case ATTR_ELEMENT_VERTEX_MOTION: { - // TODO(mai): implement - } break; - case ATTR_ELEMENT_CORNER: { - for(int f = 0; f < num_faces; f++) { - SubdFace& face = subd_faces[f]; - - if(!face.is_quad()) { - char* center = data + (subd_face_corners.size() + ngons) * stride; - attr.zero_data(center); - - float inv_num_corners = 1.0f / float(face.num_corners); - - for(int corner = 0; corner < face.num_corners; corner++) { - attr.add_with_weight(center, - data + (face.start_corner + corner) * stride, - inv_num_corners); - } - - ngons++; - } - } - } break; - case ATTR_ELEMENT_CORNER_BYTE: { - for(int f = 0; f < num_faces; f++) { - SubdFace& face = subd_faces[f]; - - if(!face.is_quad()) { - uchar* center = (uchar*)data + (subd_face_corners.size() + ngons) * stride; - - float inv_num_corners = 1.0f / float(face.num_corners); - float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f); - - for(int corner = 0; corner < face.num_corners; corner++) { - for(int i = 0; i < 4; i++) { - val[i] += float(*(data + (face.start_corner + corner) * stride + i)) * inv_num_corners; - } - } - - for(int i = 0; i < 4; i++) { - center[i] = uchar(min(max(val[i], 0.0f), 255.0f)); - } - - ngons++; - } - } - } break; - default: break; - } - } + char *data = attr.data(); + size_t stride = attr.data_sizeof(); + int ngons = 0; + + switch (attr.element) { + case ATTR_ELEMENT_VERTEX: { + for (int f = 0; f < num_faces; f++) { + SubdFace &face = subd_faces[f]; + + if (!face.is_quad()) { + char *center = data + (verts.size() - num_subd_verts + ngons) * stride; + attr.zero_data(center); + + float inv_num_corners = 1.0f / float(face.num_corners); + + for (int corner = 0; corner < face.num_corners; corner++) { + attr.add_with_weight(center, + data + subd_face_corners[face.start_corner + corner] * stride, + inv_num_corners); + } + + ngons++; + } + } + } break; + case ATTR_ELEMENT_VERTEX_MOTION: { + // TODO(mai): implement + } break; + case ATTR_ELEMENT_CORNER: { + for (int f = 0; f < num_faces; f++) { + SubdFace &face = subd_faces[f]; + + if (!face.is_quad()) { + char *center = data + (subd_face_corners.size() + ngons) * stride; + attr.zero_data(center); + + float inv_num_corners = 1.0f / float(face.num_corners); + + for (int corner = 0; corner < face.num_corners; corner++) { + attr.add_with_weight( + center, data + (face.start_corner + corner) * stride, inv_num_corners); + } + + ngons++; + } + } + } break; + case ATTR_ELEMENT_CORNER_BYTE: { + for (int f = 0; f < num_faces; f++) { + SubdFace &face = subd_faces[f]; + + if (!face.is_quad()) { + uchar *center = (uchar *)data + (subd_face_corners.size() + ngons) * stride; + + float inv_num_corners = 1.0f / float(face.num_corners); + float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + + for (int corner = 0; corner < face.num_corners; corner++) { + for (int i = 0; i < 4; i++) { + val[i] += float(*(data + (face.start_corner + corner) * stride + i)) * + inv_num_corners; + } + } + + for (int i = 0; i < 4; i++) { + center[i] = uchar(min(max(val[i], 0.0f), 255.0f)); + } + + ngons++; + } + } + } break; + default: + break; + } + } #ifdef WITH_OPENSUBDIV - /* pack patch tables */ - if(need_packed_patch_table) { - delete patch_table; - patch_table = new PackedPatchTable; - patch_table->pack(osd_data.patch_table); - } + /* pack patch tables */ + if (need_packed_patch_table) { + delete patch_table; + patch_table = new PackedPatchTable; + patch_table->pack(osd_data.patch_table); + } #endif } diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index 3ee4124ba0f..a1d61fd4db7 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -27,98 +27,106 @@ CCL_NAMESPACE_BEGIN static size_t compute_voxel_index(const int3 &resolution, size_t x, size_t y, size_t z) { - if(x == -1 || x >= resolution.x) { - return -1; - } + if (x == -1 || x >= resolution.x) { + return -1; + } - if(y == -1 || y >= resolution.y) { - return -1; - } + if (y == -1 || y >= resolution.y) { + return -1; + } - if(z == -1 || z >= resolution.z) { - return -1; - } + if (z == -1 || z >= resolution.z) { + return -1; + } - return x + y*resolution.x + z*resolution.x*resolution.y; + return x + y * resolution.x + z * resolution.x * resolution.y; } struct QuadData { - int v0, v1, v2, v3; + int v0, v1, v2, v3; - float3 normal; + float3 normal; }; enum { - QUAD_X_MIN = 0, - QUAD_X_MAX = 1, - QUAD_Y_MIN = 2, - QUAD_Y_MAX = 3, - QUAD_Z_MIN = 4, - QUAD_Z_MAX = 5, + QUAD_X_MIN = 0, + QUAD_X_MAX = 1, + QUAD_Y_MIN = 2, + QUAD_Y_MAX = 3, + QUAD_Z_MIN = 4, + QUAD_Z_MAX = 5, }; const int quads_indices[6][4] = { - /* QUAD_X_MIN */ - { 4, 0, 3, 7 }, - /* QUAD_X_MAX */ - { 1, 5, 6, 2 }, - /* QUAD_Y_MIN */ - { 4, 5, 1, 0 }, - /* QUAD_Y_MAX */ - { 3, 2, 6, 7 }, - /* QUAD_Z_MIN */ - { 0, 1, 2, 3 }, - /* QUAD_Z_MAX */ - { 5, 4, 7, 6 }, + /* QUAD_X_MIN */ + {4, 0, 3, 7}, + /* QUAD_X_MAX */ + {1, 5, 6, 2}, + /* QUAD_Y_MIN */ + {4, 5, 1, 0}, + /* QUAD_Y_MAX */ + {3, 2, 6, 7}, + /* QUAD_Z_MIN */ + {0, 1, 2, 3}, + /* QUAD_Z_MAX */ + {5, 4, 7, 6}, }; const float3 quads_normals[6] = { - /* QUAD_X_MIN */ - make_float3(-1.0f, 0.0f, 0.0f), - /* QUAD_X_MAX */ - make_float3(1.0f, 0.0f, 0.0f), - /* QUAD_Y_MIN */ - make_float3(0.0f, -1.0f, 0.0f), - /* QUAD_Y_MAX */ - make_float3(0.0f, 1.0f, 0.0f), - /* QUAD_Z_MIN */ - make_float3(0.0f, 0.0f, -1.0f), - /* QUAD_Z_MAX */ - make_float3(0.0f, 0.0f, 1.0f), + /* QUAD_X_MIN */ + make_float3(-1.0f, 0.0f, 0.0f), + /* QUAD_X_MAX */ + make_float3(1.0f, 0.0f, 0.0f), + /* QUAD_Y_MIN */ + make_float3(0.0f, -1.0f, 0.0f), + /* QUAD_Y_MAX */ + make_float3(0.0f, 1.0f, 0.0f), + /* QUAD_Z_MIN */ + make_float3(0.0f, 0.0f, -1.0f), + /* QUAD_Z_MAX */ + make_float3(0.0f, 0.0f, 1.0f), }; -static int add_vertex(int3 v, vector<int3> &vertices, int3 res, unordered_map<size_t, int> &used_verts) +static int add_vertex(int3 v, + vector<int3> &vertices, + int3 res, + unordered_map<size_t, int> &used_verts) { - size_t vert_key = v.x + v.y * (res.x+1) + v.z * (res.x+1)*(res.y+1); - unordered_map<size_t, int>::iterator it = used_verts.find(vert_key); + size_t vert_key = v.x + v.y * (res.x + 1) + v.z * (res.x + 1) * (res.y + 1); + unordered_map<size_t, int>::iterator it = used_verts.find(vert_key); - if(it != used_verts.end()) { - return it->second; - } + if (it != used_verts.end()) { + return it->second; + } - int vertex_offset = vertices.size(); - used_verts[vert_key] = vertex_offset; - vertices.push_back(v); - return vertex_offset; + int vertex_offset = vertices.size(); + used_verts[vert_key] = vertex_offset; + vertices.push_back(v); + return vertex_offset; } -static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData> &quads, int3 res, unordered_map<size_t, int> &used_verts, int face_index) +static void create_quad(int3 corners[8], + vector<int3> &vertices, + vector<QuadData> &quads, + int3 res, + unordered_map<size_t, int> &used_verts, + int face_index) { - QuadData quad; - quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts); - quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts); - quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts); - quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts); - quad.normal = quads_normals[face_index]; - - quads.push_back(quad); + QuadData quad; + quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts); + quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts); + quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts); + quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts); + quad.normal = quads_normals[face_index]; + + quads.push_back(quad); } struct VolumeParams { - int3 resolution; - float3 cell_size; - float3 start_point; - int pad_size; + int3 resolution; + float3 cell_size; + float3 start_point; + int pad_size; }; static const int CUBE_SIZE = 8; @@ -135,373 +143,365 @@ static const int CUBE_SIZE = 8; * volume to generate a tight mesh around the volume. */ class VolumeMeshBuilder { - /* Auxilliary volume that is used to check if a node already added. */ - vector<char> grid; + /* Auxilliary volume that is used to check if a node already added. */ + vector<char> grid; - /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE - * of the original volume on each axis. */ - int3 res; + /* The resolution of the auxilliary volume, set to be equal to 1/CUBE_SIZE + * of the original volume on each axis. */ + int3 res; - size_t number_of_nodes; + size_t number_of_nodes; - /* Offset due to padding in the original grid. Padding will transform the - * coordinates of the original grid from 0...res to -padding...res+padding, - * so some coordinates are negative, and we need to properly account for - * them. */ - int3 pad_offset; + /* Offset due to padding in the original grid. Padding will transform the + * coordinates of the original grid from 0...res to -padding...res+padding, + * so some coordinates are negative, and we need to properly account for + * them. */ + int3 pad_offset; - VolumeParams *params; + VolumeParams *params; -public: - VolumeMeshBuilder(VolumeParams *volume_params); + public: + VolumeMeshBuilder(VolumeParams *volume_params); - void add_node(int x, int y, int z); + void add_node(int x, int y, int z); - void add_node_with_padding(int x, int y, int z); + void add_node_with_padding(int x, int y, int z); - void create_mesh(vector<float3> &vertices, - vector<int> &indices, - vector<float3> &face_normals); + void create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals); -private: - void generate_vertices_and_quads(vector<int3> &vertices_is, - vector<QuadData> &quads); + private: + void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads); - void convert_object_space(const vector<int3> &vertices, - vector<float3> &out_vertices); + void convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices); - void convert_quads_to_tris(const vector<QuadData> &quads, - vector<int> &tris, - vector<float3> &face_normals); + void convert_quads_to_tris(const vector<QuadData> &quads, + vector<int> &tris, + vector<float3> &face_normals); }; VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params) { - params = volume_params; - number_of_nodes = 0; + params = volume_params; + number_of_nodes = 0; - const size_t x = divide_up(params->resolution.x, CUBE_SIZE); - const size_t y = divide_up(params->resolution.y, CUBE_SIZE); - const size_t z = divide_up(params->resolution.z, CUBE_SIZE); + const size_t x = divide_up(params->resolution.x, CUBE_SIZE); + const size_t y = divide_up(params->resolution.y, CUBE_SIZE); + const size_t z = divide_up(params->resolution.z, CUBE_SIZE); - /* Adding 2*pad_size since we pad in both positive and negative directions - * along the axis. */ - const size_t px = divide_up(params->resolution.x + 2*params->pad_size, CUBE_SIZE); - const size_t py = divide_up(params->resolution.y + 2*params->pad_size, CUBE_SIZE); - const size_t pz = divide_up(params->resolution.z + 2*params->pad_size, CUBE_SIZE); + /* Adding 2*pad_size since we pad in both positive and negative directions + * along the axis. */ + const size_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE); + const size_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE); + const size_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE); - res = make_int3(px, py, pz); - pad_offset = make_int3(px - x, py - y, pz - z); + res = make_int3(px, py, pz); + pad_offset = make_int3(px - x, py - y, pz - z); - grid.resize(px*py*pz, 0); + grid.resize(px * py * pz, 0); } void VolumeMeshBuilder::add_node(int x, int y, int z) { - /* Map coordinates to index space. */ - const int index_x = (x/CUBE_SIZE) + pad_offset.x; - const int index_y = (y/CUBE_SIZE) + pad_offset.y; - const int index_z = (z/CUBE_SIZE) + pad_offset.z; + /* Map coordinates to index space. */ + const int index_x = (x / CUBE_SIZE) + pad_offset.x; + const int index_y = (y / CUBE_SIZE) + pad_offset.y; + const int index_z = (z / CUBE_SIZE) + pad_offset.z; - assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0)); + assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0)); - const size_t index = compute_voxel_index(res, index_x, index_y, index_z); + const size_t index = compute_voxel_index(res, index_x, index_y, index_z); - /* We already have a node here. */ - if(grid[index] == 1) { - return; - } + /* We already have a node here. */ + if (grid[index] == 1) { + return; + } - ++number_of_nodes; + ++number_of_nodes; - grid[index] = 1; + grid[index] = 1; } void VolumeMeshBuilder::add_node_with_padding(int x, int y, int z) { - for(int px = x - params->pad_size; px < x + params->pad_size; ++px) { - for(int py = y - params->pad_size; py < y + params->pad_size; ++py) { - for(int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) { - add_node(px, py, pz); - } - } - } + for (int px = x - params->pad_size; px < x + params->pad_size; ++px) { + for (int py = y - params->pad_size; py < y + params->pad_size; ++py) { + for (int pz = z - params->pad_size; pz < z + params->pad_size; ++pz) { + add_node(px, py, pz); + } + } + } } void VolumeMeshBuilder::create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals) { - /* We create vertices in index space (is), and only convert them to object - * space when done. */ - vector<int3> vertices_is; - vector<QuadData> quads; + /* We create vertices in index space (is), and only convert them to object + * space when done. */ + vector<int3> vertices_is; + vector<QuadData> quads; - generate_vertices_and_quads(vertices_is, quads); + generate_vertices_and_quads(vertices_is, quads); - convert_object_space(vertices_is, vertices); + convert_object_space(vertices_is, vertices); - convert_quads_to_tris(quads, indices, face_normals); + convert_quads_to_tris(quads, indices, face_normals); } -void VolumeMeshBuilder::generate_vertices_and_quads( - vector<ccl::int3> &vertices_is, - vector<QuadData> &quads) +void VolumeMeshBuilder::generate_vertices_and_quads(vector<ccl::int3> &vertices_is, + vector<QuadData> &quads) { - unordered_map<size_t, int> used_verts; - - for(int z = 0; z < res.z; ++z) { - for(int y = 0; y < res.y; ++y) { - for(int x = 0; x < res.x; ++x) { - size_t voxel_index = compute_voxel_index(res, x, y, z); - if(grid[voxel_index] == 0) { - continue; - } - - /* Compute min and max coords of the node in index space. */ - int3 min = make_int3((x - pad_offset.x)*CUBE_SIZE, - (y - pad_offset.y)*CUBE_SIZE, - (z - pad_offset.z)*CUBE_SIZE); - - /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */ - int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE); - - int3 corners[8] = { - make_int3(min[0], min[1], min[2]), - make_int3(max[0], min[1], min[2]), - make_int3(max[0], max[1], min[2]), - make_int3(min[0], max[1], min[2]), - make_int3(min[0], min[1], max[2]), - make_int3(max[0], min[1], max[2]), - make_int3(max[0], max[1], max[2]), - make_int3(min[0], max[1], max[2]), - }; - - /* Only create a quad if on the border between an active and - * an inactive node. - */ - - voxel_index = compute_voxel_index(res, x - 1, y, z); - if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN); - } - - voxel_index = compute_voxel_index(res, x + 1, y, z); - if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX); - } - - voxel_index = compute_voxel_index(res, x, y - 1, z); - if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN); - } - - voxel_index = compute_voxel_index(res, x, y + 1, z); - if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX); - } - - voxel_index = compute_voxel_index(res, x, y, z - 1); - if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN); - } - - voxel_index = compute_voxel_index(res, x, y, z + 1); - if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX); - } - } - } - } + unordered_map<size_t, int> used_verts; + + for (int z = 0; z < res.z; ++z) { + for (int y = 0; y < res.y; ++y) { + for (int x = 0; x < res.x; ++x) { + size_t voxel_index = compute_voxel_index(res, x, y, z); + if (grid[voxel_index] == 0) { + continue; + } + + /* Compute min and max coords of the node in index space. */ + int3 min = make_int3((x - pad_offset.x) * CUBE_SIZE, + (y - pad_offset.y) * CUBE_SIZE, + (z - pad_offset.z) * CUBE_SIZE); + + /* Maximum is just CUBE_SIZE voxels away from minimum on each axis. */ + int3 max = make_int3(min.x + CUBE_SIZE, min.y + CUBE_SIZE, min.z + CUBE_SIZE); + + int3 corners[8] = { + make_int3(min[0], min[1], min[2]), + make_int3(max[0], min[1], min[2]), + make_int3(max[0], max[1], min[2]), + make_int3(min[0], max[1], min[2]), + make_int3(min[0], min[1], max[2]), + make_int3(max[0], min[1], max[2]), + make_int3(max[0], max[1], max[2]), + make_int3(min[0], max[1], max[2]), + }; + + /* Only create a quad if on the border between an active and + * an inactive node. + */ + + voxel_index = compute_voxel_index(res, x - 1, y, z); + if (voxel_index == -1 || grid[voxel_index] == 0) { + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN); + } + + voxel_index = compute_voxel_index(res, x + 1, y, z); + if (voxel_index == -1 || grid[voxel_index] == 0) { + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX); + } + + voxel_index = compute_voxel_index(res, x, y - 1, z); + if (voxel_index == -1 || grid[voxel_index] == 0) { + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN); + } + + voxel_index = compute_voxel_index(res, x, y + 1, z); + if (voxel_index == -1 || grid[voxel_index] == 0) { + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX); + } + + voxel_index = compute_voxel_index(res, x, y, z - 1); + if (voxel_index == -1 || grid[voxel_index] == 0) { + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN); + } + + voxel_index = compute_voxel_index(res, x, y, z + 1); + if (voxel_index == -1 || grid[voxel_index] == 0) { + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX); + } + } + } + } } void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices, - vector<float3> &out_vertices) + vector<float3> &out_vertices) { - out_vertices.reserve(vertices.size()); + out_vertices.reserve(vertices.size()); - for(size_t i = 0; i < vertices.size(); ++i) { - float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z); - vertex *= params->cell_size; - vertex += params->start_point; + for (size_t i = 0; i < vertices.size(); ++i) { + float3 vertex = make_float3(vertices[i].x, vertices[i].y, vertices[i].z); + vertex *= params->cell_size; + vertex += params->start_point; - out_vertices.push_back(vertex); - } + out_vertices.push_back(vertex); + } } void VolumeMeshBuilder::convert_quads_to_tris(const vector<QuadData> &quads, vector<int> &tris, vector<float3> &face_normals) { - int index_offset = 0; - tris.resize(quads.size()*6); - face_normals.reserve(quads.size()*2); + int index_offset = 0; + tris.resize(quads.size() * 6); + face_normals.reserve(quads.size() * 2); - for(size_t i = 0; i < quads.size(); ++i) { - tris[index_offset++] = quads[i].v0; - tris[index_offset++] = quads[i].v2; - tris[index_offset++] = quads[i].v1; + for (size_t i = 0; i < quads.size(); ++i) { + tris[index_offset++] = quads[i].v0; + tris[index_offset++] = quads[i].v2; + tris[index_offset++] = quads[i].v1; - face_normals.push_back(quads[i].normal); + face_normals.push_back(quads[i].normal); - tris[index_offset++] = quads[i].v0; - tris[index_offset++] = quads[i].v3; - tris[index_offset++] = quads[i].v2; + tris[index_offset++] = quads[i].v0; + tris[index_offset++] = quads[i].v3; + tris[index_offset++] = quads[i].v2; - face_normals.push_back(quads[i].normal); - } + face_normals.push_back(quads[i].normal); + } } /* ************************************************************************** */ struct VoxelAttributeGrid { - float *data; - int channels; + float *data; + int channels; }; -void MeshManager::create_volume_mesh(Scene *scene, - Mesh *mesh, - Progress& progress) +void MeshManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress) { - string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str()); - progress.set_status("Updating Mesh", msg); - - vector<VoxelAttributeGrid> voxel_grids; - - /* Compute volume parameters. */ - VolumeParams volume_params; - volume_params.resolution = make_int3(0, 0, 0); - - foreach(Attribute& attr, mesh->attributes.attributes) { - if(attr.element != ATTR_ELEMENT_VOXEL) { - continue; - } - - VoxelAttribute *voxel = attr.data_voxel(); - device_memory *image_memory = scene->image_manager->image_memory(voxel->slot); - int3 resolution = make_int3(image_memory->data_width, - image_memory->data_height, - image_memory->data_depth); - - if(volume_params.resolution == make_int3(0, 0, 0)) { - volume_params.resolution = resolution; - } - else if(volume_params.resolution != resolution) { - VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n"; - return; - } - - VoxelAttributeGrid voxel_grid; - voxel_grid.data = static_cast<float*>(image_memory->host_pointer); - voxel_grid.channels = image_memory->data_elements; - voxel_grids.push_back(voxel_grid); - } - - if(voxel_grids.empty()) { - return; - } - - /* Compute padding. */ - Shader *volume_shader = NULL; - int pad_size = 0; - - foreach(Shader *shader, mesh->used_shaders) { - if(!shader->has_volume) { - continue; - } - - volume_shader = shader; - - if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) { - pad_size = max(1, pad_size); - } - else if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) { - pad_size = max(2, pad_size); - } - - break; - } - - if(!volume_shader) { - return; - } - - /* Compute start point and cell size from transform. */ - Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM); - const int3 resolution = volume_params.resolution; - float3 start_point = make_float3(0.0f, 0.0f, 0.0f); - float3 cell_size = make_float3(1.0f/resolution.x, - 1.0f/resolution.y, - 1.0f/resolution.z); - - if(attr) { - const Transform *tfm = attr->data_transform(); - const Transform itfm = transform_inverse(*tfm); - start_point = transform_point(&itfm, start_point); - cell_size = transform_direction(&itfm, cell_size); - } - - volume_params.start_point = start_point; - volume_params.cell_size = cell_size; - volume_params.pad_size = pad_size; - - /* Build bounding mesh around non-empty volume cells. */ - VolumeMeshBuilder builder(&volume_params); - const float isovalue = mesh->volume_isovalue; - - for(int z = 0; z < resolution.z; ++z) { - for(int y = 0; y < resolution.y; ++y) { - for(int x = 0; x < resolution.x; ++x) { - size_t voxel_index = compute_voxel_index(resolution, x, y, z); - - for(size_t i = 0; i < voxel_grids.size(); ++i) { - const VoxelAttributeGrid &voxel_grid = voxel_grids[i]; - const int channels = voxel_grid.channels; - - for(int c = 0; c < channels; c++) { - if(voxel_grid.data[voxel_index * channels + c] >= isovalue) { - builder.add_node_with_padding(x, y, z); - break; - } - } - } - } - } - } - - /* Create mesh. */ - vector<float3> vertices; - vector<int> indices; - vector<float3> face_normals; - builder.create_mesh(vertices, indices, face_normals); - - mesh->clear(true); - mesh->reserve_mesh(vertices.size(), indices.size()/3); - mesh->used_shaders.push_back(volume_shader); - - for(size_t i = 0; i < vertices.size(); ++i) { - mesh->add_vertex(vertices[i]); - } - - for(size_t i = 0; i < indices.size(); i += 3) { - mesh->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false); - } - - Attribute *attr_fN = mesh->attributes.add(ATTR_STD_FACE_NORMAL); - float3 *fN = attr_fN->data_float3(); - - for(size_t i = 0; i < face_normals.size(); ++i) { - fN[i] = face_normals[i]; - } - - /* Print stats. */ - VLOG(1) << "Memory usage volume mesh: " - << ((vertices.size() + face_normals.size())*sizeof(float3) + indices.size()*sizeof(int))/(1024.0*1024.0) - << "Mb."; - - VLOG(1) << "Memory usage volume grid: " - << (resolution.x*resolution.y*resolution.z*sizeof(float))/(1024.0*1024.0) - << "Mb."; + string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str()); + progress.set_status("Updating Mesh", msg); + + vector<VoxelAttributeGrid> voxel_grids; + + /* Compute volume parameters. */ + VolumeParams volume_params; + volume_params.resolution = make_int3(0, 0, 0); + + foreach (Attribute &attr, mesh->attributes.attributes) { + if (attr.element != ATTR_ELEMENT_VOXEL) { + continue; + } + + VoxelAttribute *voxel = attr.data_voxel(); + device_memory *image_memory = scene->image_manager->image_memory(voxel->slot); + int3 resolution = make_int3( + image_memory->data_width, image_memory->data_height, image_memory->data_depth); + + if (volume_params.resolution == make_int3(0, 0, 0)) { + volume_params.resolution = resolution; + } + else if (volume_params.resolution != resolution) { + VLOG(1) << "Can't create volume mesh, all voxel grid resolutions must be equal\n"; + return; + } + + VoxelAttributeGrid voxel_grid; + voxel_grid.data = static_cast<float *>(image_memory->host_pointer); + voxel_grid.channels = image_memory->data_elements; + voxel_grids.push_back(voxel_grid); + } + + if (voxel_grids.empty()) { + return; + } + + /* Compute padding. */ + Shader *volume_shader = NULL; + int pad_size = 0; + + foreach (Shader *shader, mesh->used_shaders) { + if (!shader->has_volume) { + continue; + } + + volume_shader = shader; + + if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_LINEAR) { + pad_size = max(1, pad_size); + } + else if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) { + pad_size = max(2, pad_size); + } + + break; + } + + if (!volume_shader) { + return; + } + + /* Compute start point and cell size from transform. */ + Attribute *attr = mesh->attributes.find(ATTR_STD_GENERATED_TRANSFORM); + const int3 resolution = volume_params.resolution; + float3 start_point = make_float3(0.0f, 0.0f, 0.0f); + float3 cell_size = make_float3(1.0f / resolution.x, 1.0f / resolution.y, 1.0f / resolution.z); + + if (attr) { + const Transform *tfm = attr->data_transform(); + const Transform itfm = transform_inverse(*tfm); + start_point = transform_point(&itfm, start_point); + cell_size = transform_direction(&itfm, cell_size); + } + + volume_params.start_point = start_point; + volume_params.cell_size = cell_size; + volume_params.pad_size = pad_size; + + /* Build bounding mesh around non-empty volume cells. */ + VolumeMeshBuilder builder(&volume_params); + const float isovalue = mesh->volume_isovalue; + + for (int z = 0; z < resolution.z; ++z) { + for (int y = 0; y < resolution.y; ++y) { + for (int x = 0; x < resolution.x; ++x) { + size_t voxel_index = compute_voxel_index(resolution, x, y, z); + + for (size_t i = 0; i < voxel_grids.size(); ++i) { + const VoxelAttributeGrid &voxel_grid = voxel_grids[i]; + const int channels = voxel_grid.channels; + + for (int c = 0; c < channels; c++) { + if (voxel_grid.data[voxel_index * channels + c] >= isovalue) { + builder.add_node_with_padding(x, y, z); + break; + } + } + } + } + } + } + + /* Create mesh. */ + vector<float3> vertices; + vector<int> indices; + vector<float3> face_normals; + builder.create_mesh(vertices, indices, face_normals); + + mesh->clear(true); + mesh->reserve_mesh(vertices.size(), indices.size() / 3); + mesh->used_shaders.push_back(volume_shader); + + for (size_t i = 0; i < vertices.size(); ++i) { + mesh->add_vertex(vertices[i]); + } + + for (size_t i = 0; i < indices.size(); i += 3) { + mesh->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false); + } + + Attribute *attr_fN = mesh->attributes.add(ATTR_STD_FACE_NORMAL); + float3 *fN = attr_fN->data_float3(); + + for (size_t i = 0; i < face_normals.size(); ++i) { + fN[i] = face_normals[i]; + } + + /* Print stats. */ + VLOG(1) << "Memory usage volume mesh: " + << ((vertices.size() + face_normals.size()) * sizeof(float3) + + indices.size() * sizeof(int)) / + (1024.0 * 1024.0) + << "Mb."; + + VLOG(1) << "Memory usage volume grid: " + << (resolution.x * resolution.y * resolution.z * sizeof(float)) / (1024.0 * 1024.0) + << "Mb."; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index cc9dd8f2679..f3572ee1585 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -37,36 +37,36 @@ CCL_NAMESPACE_BEGIN /* Texture Mapping */ #define TEXTURE_MAPPING_DEFINE(TextureNode) \ - SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ - SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ - SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ - \ - SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ - SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \ - SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \ - \ - static NodeEnum mapping_axis_enum; \ - mapping_axis_enum.insert("none", TextureMapping::NONE); \ - mapping_axis_enum.insert("x", TextureMapping::X); \ - mapping_axis_enum.insert("y", TextureMapping::Y); \ - mapping_axis_enum.insert("z", TextureMapping::Z); \ - SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \ - SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \ - SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \ - \ - static NodeEnum mapping_type_enum; \ - mapping_type_enum.insert("point", TextureMapping::POINT); \ - mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \ - mapping_type_enum.insert("vector", TextureMapping::VECTOR); \ - mapping_type_enum.insert("normal", TextureMapping::NORMAL); \ - SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \ - \ - static NodeEnum mapping_projection_enum; \ - mapping_projection_enum.insert("flat", TextureMapping::FLAT); \ - mapping_projection_enum.insert("cube", TextureMapping::CUBE); \ - mapping_projection_enum.insert("tube", TextureMapping::TUBE); \ - mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \ - SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT); + SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ + SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ + SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ +\ + SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ + SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \ + SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \ +\ + static NodeEnum mapping_axis_enum; \ + mapping_axis_enum.insert("none", TextureMapping::NONE); \ + mapping_axis_enum.insert("x", TextureMapping::X); \ + mapping_axis_enum.insert("y", TextureMapping::Y); \ + mapping_axis_enum.insert("z", TextureMapping::Z); \ + SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \ + SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \ + SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \ +\ + static NodeEnum mapping_type_enum; \ + mapping_type_enum.insert("point", TextureMapping::POINT); \ + mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \ + mapping_type_enum.insert("vector", TextureMapping::VECTOR); \ + mapping_type_enum.insert("normal", TextureMapping::NORMAL); \ + SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \ +\ + static NodeEnum mapping_projection_enum; \ + mapping_projection_enum.insert("flat", TextureMapping::FLAT); \ + mapping_projection_enum.insert("cube", TextureMapping::CUBE); \ + mapping_projection_enum.insert("tube", TextureMapping::TUBE); \ + mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \ + SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT); TextureMapping::TextureMapping() { @@ -74,6146 +74,6096 @@ TextureMapping::TextureMapping() Transform TextureMapping::compute_transform() { - Transform mmat = transform_scale(make_float3(0.0f, 0.0f, 0.0f)); - - if(x_mapping != NONE) - mmat[0][x_mapping-1] = 1.0f; - if(y_mapping != NONE) - mmat[1][y_mapping-1] = 1.0f; - if(z_mapping != NONE) - mmat[2][z_mapping-1] = 1.0f; - - float3 scale_clamped = scale; - - if(type == TEXTURE || type == NORMAL) { - /* keep matrix invertible */ - if(fabsf(scale.x) < 1e-5f) - scale_clamped.x = signf(scale.x)*1e-5f; - if(fabsf(scale.y) < 1e-5f) - scale_clamped.y = signf(scale.y)*1e-5f; - if(fabsf(scale.z) < 1e-5f) - scale_clamped.z = signf(scale.z)*1e-5f; - } - - Transform smat = transform_scale(scale_clamped); - Transform rmat = transform_euler(rotation); - Transform tmat = transform_translate(translation); - - Transform mat; - - switch(type) { - case TEXTURE: - /* inverse transform on texture coordinate gives - * forward transform on texture */ - mat = tmat*rmat*smat; - mat = transform_inverse(mat); - break; - case POINT: - /* full transform */ - mat = tmat*rmat*smat; - break; - case VECTOR: - /* no translation for vectors */ - mat = rmat*smat; - break; - case NORMAL: - /* no translation for normals, and inverse transpose */ - mat = rmat*smat; - mat = transform_transposed_inverse(mat); - break; - } - - /* projection last */ - mat = mat*mmat; - - return mat; + Transform mmat = transform_scale(make_float3(0.0f, 0.0f, 0.0f)); + + if (x_mapping != NONE) + mmat[0][x_mapping - 1] = 1.0f; + if (y_mapping != NONE) + mmat[1][y_mapping - 1] = 1.0f; + if (z_mapping != NONE) + mmat[2][z_mapping - 1] = 1.0f; + + float3 scale_clamped = scale; + + if (type == TEXTURE || type == NORMAL) { + /* keep matrix invertible */ + if (fabsf(scale.x) < 1e-5f) + scale_clamped.x = signf(scale.x) * 1e-5f; + if (fabsf(scale.y) < 1e-5f) + scale_clamped.y = signf(scale.y) * 1e-5f; + if (fabsf(scale.z) < 1e-5f) + scale_clamped.z = signf(scale.z) * 1e-5f; + } + + Transform smat = transform_scale(scale_clamped); + Transform rmat = transform_euler(rotation); + Transform tmat = transform_translate(translation); + + Transform mat; + + switch (type) { + case TEXTURE: + /* inverse transform on texture coordinate gives + * forward transform on texture */ + mat = tmat * rmat * smat; + mat = transform_inverse(mat); + break; + case POINT: + /* full transform */ + mat = tmat * rmat * smat; + break; + case VECTOR: + /* no translation for vectors */ + mat = rmat * smat; + break; + case NORMAL: + /* no translation for normals, and inverse transpose */ + mat = rmat * smat; + mat = transform_transposed_inverse(mat); + break; + } + + /* projection last */ + mat = mat * mmat; + + return mat; } bool TextureMapping::skip() { - if(translation != make_float3(0.0f, 0.0f, 0.0f)) - return false; - if(rotation != make_float3(0.0f, 0.0f, 0.0f)) - return false; - if(scale != make_float3(1.0f, 1.0f, 1.0f)) - return false; + if (translation != make_float3(0.0f, 0.0f, 0.0f)) + return false; + if (rotation != make_float3(0.0f, 0.0f, 0.0f)) + return false; + if (scale != make_float3(1.0f, 1.0f, 1.0f)) + return false; - if(x_mapping != X || y_mapping != Y || z_mapping != Z) - return false; - if(use_minmax) - return false; + if (x_mapping != X || y_mapping != Y || z_mapping != Z) + return false; + if (use_minmax) + return false; - return true; + return true; } -void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_out) +void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out) { - compiler.add_node(NODE_MAPPING, offset_in, offset_out); + compiler.add_node(NODE_MAPPING, offset_in, offset_out); - Transform tfm = compute_transform(); - compiler.add_node(tfm.x); - compiler.add_node(tfm.y); - compiler.add_node(tfm.z); + Transform tfm = compute_transform(); + compiler.add_node(tfm.x); + compiler.add_node(tfm.y); + compiler.add_node(tfm.z); - if(use_minmax) { - compiler.add_node(NODE_MIN_MAX, offset_out, offset_out); - compiler.add_node(float3_to_float4(min)); - compiler.add_node(float3_to_float4(max)); - } + if (use_minmax) { + compiler.add_node(NODE_MIN_MAX, offset_out, offset_out); + compiler.add_node(float3_to_float4(min)); + compiler.add_node(float3_to_float4(max)); + } - if(type == NORMAL) { - compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out); - compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out); - } + if (type == NORMAL) { + compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out); + compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out); + } } /* Convenience function for texture nodes, allocating stack space to output * a modified vector and returning its offset */ -int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in) +int TextureMapping::compile_begin(SVMCompiler &compiler, ShaderInput *vector_in) { - if(!skip()) { - int offset_in = compiler.stack_assign(vector_in); - int offset_out = compiler.stack_find_offset(SocketType::VECTOR); + if (!skip()) { + int offset_in = compiler.stack_assign(vector_in); + int offset_out = compiler.stack_find_offset(SocketType::VECTOR); - compile(compiler, offset_in, offset_out); + compile(compiler, offset_in, offset_out); - return offset_out; - } + return offset_out; + } - return compiler.stack_assign(vector_in); + return compiler.stack_assign(vector_in); } -void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset) +void TextureMapping::compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset) { - if(!skip()) { - compiler.stack_clear_offset(vector_in->type(), vector_offset); - } + if (!skip()) { + compiler.stack_clear_offset(vector_in->type(), vector_offset); + } } void TextureMapping::compile(OSLCompiler &compiler) { - if(!skip()) { - compiler.parameter("mapping", compute_transform()); - compiler.parameter("use_mapping", 1); - } + if (!skip()) { + compiler.parameter("mapping", compute_transform()); + compiler.parameter("use_mapping", 1); + } } /* Image Texture */ NODE_DEFINE(ImageTextureNode) { - NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(ImageTextureNode); + TEXTURE_MAPPING_DEFINE(ImageTextureNode); - SOCKET_STRING(filename, "Filename", ustring()); + SOCKET_STRING(filename, "Filename", ustring()); - static NodeEnum color_space_enum; - color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); - color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); - SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); + static NodeEnum color_space_enum; + color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); + color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); + SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); - SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); + SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); - static NodeEnum interpolation_enum; - interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); - interpolation_enum.insert("linear", INTERPOLATION_LINEAR); - interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); - interpolation_enum.insert("smart", INTERPOLATION_SMART); - SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); - static NodeEnum extension_enum; - extension_enum.insert("periodic", EXTENSION_REPEAT); - extension_enum.insert("clamp", EXTENSION_EXTEND); - extension_enum.insert("black", EXTENSION_CLIP); - SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT); + static NodeEnum extension_enum; + extension_enum.insert("periodic", EXTENSION_REPEAT); + extension_enum.insert("clamp", EXTENSION_EXTEND); + extension_enum.insert("black", EXTENSION_CLIP); + SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT); - static NodeEnum projection_enum; - projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT); - projection_enum.insert("box", NODE_IMAGE_PROJ_BOX); - projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE); - projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE); - SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT); + static NodeEnum projection_enum; + projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT); + projection_enum.insert("box", NODE_IMAGE_PROJ_BOX); + projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE); + projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE); + SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT); - SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f); + SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(alpha, "Alpha"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); - return type; + return type; } -ImageTextureNode::ImageTextureNode() -: ImageSlotTextureNode(node_type) +ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type) { - image_manager = NULL; - slot = -1; - is_float = -1; - is_linear = false; - builtin_data = NULL; - animated = false; + image_manager = NULL; + slot = -1; + is_float = -1; + is_linear = false; + builtin_data = NULL; + animated = false; } ImageTextureNode::~ImageTextureNode() { - if(image_manager) { - image_manager->remove_image(filename.string(), - builtin_data, - interpolation, - extension, - use_alpha); - } + if (image_manager) { + image_manager->remove_image( + filename.string(), builtin_data, interpolation, extension, use_alpha); + } } ShaderNode *ImageTextureNode::clone() const { - ImageTextureNode *node = new ImageTextureNode(*this); - node->image_manager = NULL; - node->slot = -1; - node->is_float = -1; - node->is_linear = false; - return node; + ImageTextureNode *node = new ImageTextureNode(*this); + node->image_manager = NULL; + node->slot = -1; + node->is_float = -1; + node->is_linear = false; + return node; } void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) { #ifdef WITH_PTEX - /* todo: avoid loading other texture coordinates when using ptex, - * and hide texture coordinate socket in the UI */ - if(shader->has_surface && string_endswith(filename, ".ptx")) { - /* ptex */ - attributes->add(ATTR_STD_PTEX_FACE_ID); - attributes->add(ATTR_STD_PTEX_UV); - } + /* todo: avoid loading other texture coordinates when using ptex, + * and hide texture coordinate socket in the UI */ + if (shader->has_surface && string_endswith(filename, ".ptx")) { + /* ptex */ + attributes->add(ATTR_STD_PTEX_FACE_ID); + attributes->add(ATTR_STD_PTEX_UV); + } #endif - ShaderNode::attributes(shader, attributes); -} - -void ImageTextureNode::compile(SVMCompiler& compiler) -{ - ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *alpha_out = output("Alpha"); - - image_manager = compiler.image_manager; - if(is_float == -1) { - ImageMetaData metadata; - slot = image_manager->add_image(filename.string(), - builtin_data, - animated, - 0, - interpolation, - extension, - use_alpha, - metadata); - is_float = metadata.is_float; - is_linear = metadata.is_linear; - } - - if(slot != -1) { - int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1; - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - - if(projection != NODE_IMAGE_PROJ_BOX) { - compiler.add_node(NODE_TEX_IMAGE, - slot, - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out), - srgb), - projection); - } - else { - compiler.add_node(NODE_TEX_IMAGE_BOX, - slot, - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out), - srgb), - __float_as_int(projection_blend)); - } - - tex_mapping.compile_end(compiler, vector_in, vector_offset); - } - else { - /* image not found */ - if(!color_out->links.empty()) { - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); - compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R, - TEX_IMAGE_MISSING_G, - TEX_IMAGE_MISSING_B)); - } - if(!alpha_out->links.empty()) - compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out)); - } -} - -void ImageTextureNode::compile(OSLCompiler& compiler) -{ - ShaderOutput *alpha_out = output("Alpha"); - - tex_mapping.compile(compiler); - - image_manager = compiler.image_manager; - if(is_float == -1) { - ImageMetaData metadata; - if(builtin_data == NULL) { - image_manager->get_image_metadata(filename.string(), NULL, metadata); - } - else { - slot = image_manager->add_image(filename.string(), - builtin_data, - animated, - 0, - interpolation, - extension, - use_alpha, - metadata); - } - is_float = metadata.is_float; - is_linear = metadata.is_linear; - } - - if(slot == -1) { - compiler.parameter(this, "filename"); - } - else { - /* TODO(sergey): It's not so simple to pass custom attribute - * to the texture() function in order to make builtin images - * support more clear. So we use special file name which is - * "@i<slot_number>" and check whether file name matches this - * mask in the OSLRenderServices::texture(). - */ - compiler.parameter("filename", string_printf("@i%d", slot).c_str()); - } - if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) - compiler.parameter("color_space", "linear"); - else - compiler.parameter("color_space", "sRGB"); - compiler.parameter(this, "projection"); - compiler.parameter(this, "projection_blend"); - compiler.parameter("is_float", is_float); - compiler.parameter("use_alpha", !alpha_out->links.empty()); - compiler.parameter(this, "interpolation"); - compiler.parameter(this, "extension"); - - compiler.add(this, "node_image_texture"); + ShaderNode::attributes(shader, attributes); +} + +void ImageTextureNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *alpha_out = output("Alpha"); + + image_manager = compiler.image_manager; + if (is_float == -1) { + ImageMetaData metadata; + slot = image_manager->add_image(filename.string(), + builtin_data, + animated, + 0, + interpolation, + extension, + use_alpha, + metadata); + is_float = metadata.is_float; + is_linear = metadata.is_linear; + } + + if (slot != -1) { + int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR) ? 0 : 1; + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + + if (projection != NODE_IMAGE_PROJ_BOX) { + compiler.add_node(NODE_TEX_IMAGE, + slot, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out), + srgb), + projection); + } + else { + compiler.add_node(NODE_TEX_IMAGE_BOX, + slot, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out), + srgb), + __float_as_int(projection_blend)); + } + + tex_mapping.compile_end(compiler, vector_in, vector_offset); + } + else { + /* image not found */ + if (!color_out->links.empty()) { + compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); + compiler.add_node( + NODE_VALUE_V, + make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B)); + } + if (!alpha_out->links.empty()) + compiler.add_node( + NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out)); + } +} + +void ImageTextureNode::compile(OSLCompiler &compiler) +{ + ShaderOutput *alpha_out = output("Alpha"); + + tex_mapping.compile(compiler); + + image_manager = compiler.image_manager; + if (is_float == -1) { + ImageMetaData metadata; + if (builtin_data == NULL) { + image_manager->get_image_metadata(filename.string(), NULL, metadata); + } + else { + slot = image_manager->add_image(filename.string(), + builtin_data, + animated, + 0, + interpolation, + extension, + use_alpha, + metadata); + } + is_float = metadata.is_float; + is_linear = metadata.is_linear; + } + + if (slot == -1) { + compiler.parameter(this, "filename"); + } + else { + /* TODO(sergey): It's not so simple to pass custom attribute + * to the texture() function in order to make builtin images + * support more clear. So we use special file name which is + * "@i<slot_number>" and check whether file name matches this + * mask in the OSLRenderServices::texture(). + */ + compiler.parameter("filename", string_printf("@i%d", slot).c_str()); + } + if (is_linear || color_space != NODE_COLOR_SPACE_COLOR) + compiler.parameter("color_space", "linear"); + else + compiler.parameter("color_space", "sRGB"); + compiler.parameter(this, "projection"); + compiler.parameter(this, "projection_blend"); + compiler.parameter("is_float", is_float); + compiler.parameter("use_alpha", !alpha_out->links.empty()); + compiler.parameter(this, "interpolation"); + compiler.parameter(this, "extension"); + + compiler.add(this, "node_image_texture"); } /* Environment Texture */ NODE_DEFINE(EnvironmentTextureNode) { - NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("environment_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode); + TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode); - SOCKET_STRING(filename, "Filename", ustring()); + SOCKET_STRING(filename, "Filename", ustring()); - static NodeEnum color_space_enum; - color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); - color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); - SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); + static NodeEnum color_space_enum; + color_space_enum.insert("none", NODE_COLOR_SPACE_NONE); + color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR); + SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR); - SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); + SOCKET_BOOLEAN(use_alpha, "Use Alpha", true); - static NodeEnum interpolation_enum; - interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); - interpolation_enum.insert("linear", INTERPOLATION_LINEAR); - interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); - interpolation_enum.insert("smart", INTERPOLATION_SMART); - SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); - static NodeEnum projection_enum; - projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR); - projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL); - SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR); + static NodeEnum projection_enum; + projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR); + projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL); + SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(alpha, "Alpha"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); - return type; + return type; } -EnvironmentTextureNode::EnvironmentTextureNode() -: ImageSlotTextureNode(node_type) +EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_type) { - image_manager = NULL; - slot = -1; - is_float = -1; - is_linear = false; - builtin_data = NULL; - animated = false; + image_manager = NULL; + slot = -1; + is_float = -1; + is_linear = false; + builtin_data = NULL; + animated = false; } EnvironmentTextureNode::~EnvironmentTextureNode() { - if(image_manager) { - image_manager->remove_image(filename.string(), - builtin_data, - interpolation, - EXTENSION_REPEAT, - use_alpha); - } + if (image_manager) { + image_manager->remove_image( + filename.string(), builtin_data, interpolation, EXTENSION_REPEAT, use_alpha); + } } ShaderNode *EnvironmentTextureNode::clone() const { - EnvironmentTextureNode *node = new EnvironmentTextureNode(*this); - node->image_manager = NULL; - node->slot = -1; - node->is_float = -1; - node->is_linear = false; - return node; + EnvironmentTextureNode *node = new EnvironmentTextureNode(*this); + node->image_manager = NULL; + node->slot = -1; + node->is_float = -1; + node->is_linear = false; + return node; } void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) { #ifdef WITH_PTEX - if(shader->has_surface && string_endswith(filename, ".ptx")) { - /* ptex */ - attributes->add(ATTR_STD_PTEX_FACE_ID); - attributes->add(ATTR_STD_PTEX_UV); - } + if (shader->has_surface && string_endswith(filename, ".ptx")) { + /* ptex */ + attributes->add(ATTR_STD_PTEX_FACE_ID); + attributes->add(ATTR_STD_PTEX_UV); + } #endif - ShaderNode::attributes(shader, attributes); -} - -void EnvironmentTextureNode::compile(SVMCompiler& compiler) -{ - ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *alpha_out = output("Alpha"); - - image_manager = compiler.image_manager; - if(slot == -1) { - ImageMetaData metadata; - slot = image_manager->add_image(filename.string(), - builtin_data, - animated, - 0, - interpolation, - EXTENSION_REPEAT, - use_alpha, - metadata); - is_float = metadata.is_float; - is_linear = metadata.is_linear; - } - - if(slot != -1) { - int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1; - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - - compiler.add_node(NODE_TEX_ENVIRONMENT, - slot, - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out), - srgb), - projection); - - tex_mapping.compile_end(compiler, vector_in, vector_offset); - } - else { - /* image not found */ - if(!color_out->links.empty()) { - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); - compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R, - TEX_IMAGE_MISSING_G, - TEX_IMAGE_MISSING_B)); - } - if(!alpha_out->links.empty()) - compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out)); - } -} - -void EnvironmentTextureNode::compile(OSLCompiler& compiler) -{ - ShaderOutput *alpha_out = output("Alpha"); - - tex_mapping.compile(compiler); - - /* See comments in ImageTextureNode::compile about support - * of builtin images. - */ - image_manager = compiler.image_manager; - if(is_float == -1) { - ImageMetaData metadata; - if(builtin_data == NULL) { - image_manager->get_image_metadata(filename.string(), NULL, metadata); - } - else { - slot = image_manager->add_image(filename.string(), - builtin_data, - animated, - 0, - interpolation, - EXTENSION_REPEAT, - use_alpha, - metadata); - } - is_float = metadata.is_float; - is_linear = metadata.is_linear; - } - - if(slot == -1) { - compiler.parameter(this, "filename"); - } - else { - compiler.parameter("filename", string_printf("@i%d", slot).c_str()); - } - compiler.parameter(this, "projection"); - if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) - compiler.parameter("color_space", "linear"); - else - compiler.parameter("color_space", "sRGB"); - - compiler.parameter(this, "interpolation"); - compiler.parameter("is_float", is_float); - compiler.parameter("use_alpha", !alpha_out->links.empty()); - compiler.add(this, "node_environment_texture"); + ShaderNode::attributes(shader, attributes); +} + +void EnvironmentTextureNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *alpha_out = output("Alpha"); + + image_manager = compiler.image_manager; + if (slot == -1) { + ImageMetaData metadata; + slot = image_manager->add_image(filename.string(), + builtin_data, + animated, + 0, + interpolation, + EXTENSION_REPEAT, + use_alpha, + metadata); + is_float = metadata.is_float; + is_linear = metadata.is_linear; + } + + if (slot != -1) { + int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR) ? 0 : 1; + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + + compiler.add_node(NODE_TEX_ENVIRONMENT, + slot, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out), + srgb), + projection); + + tex_mapping.compile_end(compiler, vector_in, vector_offset); + } + else { + /* image not found */ + if (!color_out->links.empty()) { + compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); + compiler.add_node( + NODE_VALUE_V, + make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B)); + } + if (!alpha_out->links.empty()) + compiler.add_node( + NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out)); + } +} + +void EnvironmentTextureNode::compile(OSLCompiler &compiler) +{ + ShaderOutput *alpha_out = output("Alpha"); + + tex_mapping.compile(compiler); + + /* See comments in ImageTextureNode::compile about support + * of builtin images. + */ + image_manager = compiler.image_manager; + if (is_float == -1) { + ImageMetaData metadata; + if (builtin_data == NULL) { + image_manager->get_image_metadata(filename.string(), NULL, metadata); + } + else { + slot = image_manager->add_image(filename.string(), + builtin_data, + animated, + 0, + interpolation, + EXTENSION_REPEAT, + use_alpha, + metadata); + } + is_float = metadata.is_float; + is_linear = metadata.is_linear; + } + + if (slot == -1) { + compiler.parameter(this, "filename"); + } + else { + compiler.parameter("filename", string_printf("@i%d", slot).c_str()); + } + compiler.parameter(this, "projection"); + if (is_linear || color_space != NODE_COLOR_SPACE_COLOR) + compiler.parameter("color_space", "linear"); + else + compiler.parameter("color_space", "sRGB"); + + compiler.parameter(this, "interpolation"); + compiler.parameter("is_float", is_float); + compiler.parameter("use_alpha", !alpha_out->links.empty()); + compiler.add(this, "node_environment_texture"); } /* Sky Texture */ static float2 sky_spherical_coordinates(float3 dir) { - return make_float2(acosf(dir.z), atan2f(dir.x, dir.y)); + return make_float2(acosf(dir.z), atan2f(dir.x, dir.y)); } typedef struct SunSky { - /* sun direction in spherical and cartesian */ - float theta, phi; + /* sun direction in spherical and cartesian */ + float theta, phi; - /* Parameter */ - float radiance_x, radiance_y, radiance_z; - float config_x[9], config_y[9], config_z[9]; + /* Parameter */ + float radiance_x, radiance_y, radiance_z; + float config_x[9], config_y[9], config_z[9]; } SunSky; /* Preetham model */ static float sky_perez_function(float lam[6], float theta, float gamma) { - return (1.0f + lam[0]*expf(lam[1]/cosf(theta))) * (1.0f + lam[2]*expf(lam[3]*gamma) + lam[4]*cosf(gamma)*cosf(gamma)); + return (1.0f + lam[0] * expf(lam[1] / cosf(theta))) * + (1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma)); } static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity) { - /* - * We re-use the SunSky struct of the new model, to avoid extra variables - * zenith_Y/x/y is now radiance_x/y/z - * perez_Y/x/y is now config_x/y/z - */ - - float2 spherical = sky_spherical_coordinates(dir); - float theta = spherical.x; - float phi = spherical.y; - - sunsky->theta = theta; - sunsky->phi = phi; - - float theta2 = theta*theta; - float theta3 = theta2*theta; - float T = turbidity; - float T2 = T * T; - - float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta); - sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f; - sunsky->radiance_x *= 0.06f; - - sunsky->radiance_y = - (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 + - (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T + - (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f); - - sunsky->radiance_z = - (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 + - (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T + - (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f); - - sunsky->config_x[0] = (0.1787f * T - 1.4630f); - sunsky->config_x[1] = (-0.3554f * T + 0.4275f); - sunsky->config_x[2] = (-0.0227f * T + 5.3251f); - sunsky->config_x[3] = (0.1206f * T - 2.5771f); - sunsky->config_x[4] = (-0.0670f * T + 0.3703f); - - sunsky->config_y[0] = (-0.0193f * T - 0.2592f); - sunsky->config_y[1] = (-0.0665f * T + 0.0008f); - sunsky->config_y[2] = (-0.0004f * T + 0.2125f); - sunsky->config_y[3] = (-0.0641f * T - 0.8989f); - sunsky->config_y[4] = (-0.0033f * T + 0.0452f); - - sunsky->config_z[0] = (-0.0167f * T - 0.2608f); - sunsky->config_z[1] = (-0.0950f * T + 0.0092f); - sunsky->config_z[2] = (-0.0079f * T + 0.2102f); - sunsky->config_z[3] = (-0.0441f * T - 1.6537f); - sunsky->config_z[4] = (-0.0109f * T + 0.0529f); - - /* unused for old sky model */ - for(int i = 5; i < 9; i++) { - sunsky->config_x[i] = 0.0f; - sunsky->config_y[i] = 0.0f; - sunsky->config_z[i] = 0.0f; - } - - sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta); - sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta); - sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta); + /* + * We re-use the SunSky struct of the new model, to avoid extra variables + * zenith_Y/x/y is now radiance_x/y/z + * perez_Y/x/y is now config_x/y/z + */ + + float2 spherical = sky_spherical_coordinates(dir); + float theta = spherical.x; + float phi = spherical.y; + + sunsky->theta = theta; + sunsky->phi = phi; + + float theta2 = theta * theta; + float theta3 = theta2 * theta; + float T = turbidity; + float T2 = T * T; + + float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta); + sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f; + sunsky->radiance_x *= 0.06f; + + sunsky->radiance_y = (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 + + (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T + + (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f); + + sunsky->radiance_z = (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 + + (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T + + (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f); + + sunsky->config_x[0] = (0.1787f * T - 1.4630f); + sunsky->config_x[1] = (-0.3554f * T + 0.4275f); + sunsky->config_x[2] = (-0.0227f * T + 5.3251f); + sunsky->config_x[3] = (0.1206f * T - 2.5771f); + sunsky->config_x[4] = (-0.0670f * T + 0.3703f); + + sunsky->config_y[0] = (-0.0193f * T - 0.2592f); + sunsky->config_y[1] = (-0.0665f * T + 0.0008f); + sunsky->config_y[2] = (-0.0004f * T + 0.2125f); + sunsky->config_y[3] = (-0.0641f * T - 0.8989f); + sunsky->config_y[4] = (-0.0033f * T + 0.0452f); + + sunsky->config_z[0] = (-0.0167f * T - 0.2608f); + sunsky->config_z[1] = (-0.0950f * T + 0.0092f); + sunsky->config_z[2] = (-0.0079f * T + 0.2102f); + sunsky->config_z[3] = (-0.0441f * T - 1.6537f); + sunsky->config_z[4] = (-0.0109f * T + 0.0529f); + + /* unused for old sky model */ + for (int i = 5; i < 9; i++) { + sunsky->config_x[i] = 0.0f; + sunsky->config_y[i] = 0.0f; + sunsky->config_z[i] = 0.0f; + } + + sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta); + sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta); + sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta); } /* Hosek / Wilkie */ -static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidity, float ground_albedo) +static void sky_texture_precompute_new(SunSky *sunsky, + float3 dir, + float turbidity, + float ground_albedo) { - /* Calculate Sun Direction and save coordinates */ - float2 spherical = sky_spherical_coordinates(dir); - float theta = spherical.x; - float phi = spherical.y; + /* Calculate Sun Direction and save coordinates */ + float2 spherical = sky_spherical_coordinates(dir); + float theta = spherical.x; + float phi = spherical.y; - /* Clamp Turbidity */ - turbidity = clamp(turbidity, 0.0f, 10.0f); + /* Clamp Turbidity */ + turbidity = clamp(turbidity, 0.0f, 10.0f); - /* Clamp to Horizon */ - theta = clamp(theta, 0.0f, M_PI_2_F); + /* Clamp to Horizon */ + theta = clamp(theta, 0.0f, M_PI_2_F); - sunsky->theta = theta; - sunsky->phi = phi; + sunsky->theta = theta; + sunsky->phi = phi; - float solarElevation = M_PI_2_F - theta; + float solarElevation = M_PI_2_F - theta; - /* Initialize Sky Model */ - ArHosekSkyModelState *sky_state; - sky_state = arhosek_xyz_skymodelstate_alloc_init((double)turbidity, (double)ground_albedo, (double)solarElevation); + /* Initialize Sky Model */ + ArHosekSkyModelState *sky_state; + sky_state = arhosek_xyz_skymodelstate_alloc_init( + (double)turbidity, (double)ground_albedo, (double)solarElevation); - /* Copy values from sky_state to SunSky */ - for(int i = 0; i < 9; ++i) { - sunsky->config_x[i] = (float)sky_state->configs[0][i]; - sunsky->config_y[i] = (float)sky_state->configs[1][i]; - sunsky->config_z[i] = (float)sky_state->configs[2][i]; - } - sunsky->radiance_x = (float)sky_state->radiances[0]; - sunsky->radiance_y = (float)sky_state->radiances[1]; - sunsky->radiance_z = (float)sky_state->radiances[2]; + /* Copy values from sky_state to SunSky */ + for (int i = 0; i < 9; ++i) { + sunsky->config_x[i] = (float)sky_state->configs[0][i]; + sunsky->config_y[i] = (float)sky_state->configs[1][i]; + sunsky->config_z[i] = (float)sky_state->configs[2][i]; + } + sunsky->radiance_x = (float)sky_state->radiances[0]; + sunsky->radiance_y = (float)sky_state->radiances[1]; + sunsky->radiance_z = (float)sky_state->radiances[2]; - /* Free sky_state */ - arhosekskymodelstate_free(sky_state); + /* Free sky_state */ + arhosekskymodelstate_free(sky_state); } NODE_DEFINE(SkyTextureNode) { - NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER); - - TEXTURE_MAPPING_DEFINE(SkyTextureNode); - - static NodeEnum type_enum; - type_enum.insert("preetham", NODE_SKY_OLD); - type_enum.insert("hosek_wilkie", NODE_SKY_NEW); - SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW); - - SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f)); - SOCKET_FLOAT(turbidity, "Turbidity", 2.2f); - SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f); - - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - - SOCKET_OUT_COLOR(color, "Color"); - - return type; -} - -SkyTextureNode::SkyTextureNode() -: TextureNode(node_type) -{ -} - -void SkyTextureNode::compile(SVMCompiler& compiler) -{ - ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); - - SunSky sunsky; - if(type == NODE_SKY_OLD) - sky_texture_precompute_old(&sunsky, sun_direction, turbidity); - else if(type == NODE_SKY_NEW) - sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); - else - assert(false); - - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - - compiler.stack_assign(color_out); - compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type); - compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y)); - compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2])); - compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6])); - compiler.add_node(__float_as_uint(sunsky.config_x[7]), __float_as_uint(sunsky.config_x[8]), __float_as_uint(sunsky.config_y[0]), __float_as_uint(sunsky.config_y[1])); - compiler.add_node(__float_as_uint(sunsky.config_y[2]), __float_as_uint(sunsky.config_y[3]), __float_as_uint(sunsky.config_y[4]), __float_as_uint(sunsky.config_y[5])); - compiler.add_node(__float_as_uint(sunsky.config_y[6]), __float_as_uint(sunsky.config_y[7]), __float_as_uint(sunsky.config_y[8]), __float_as_uint(sunsky.config_z[0])); - compiler.add_node(__float_as_uint(sunsky.config_z[1]), __float_as_uint(sunsky.config_z[2]), __float_as_uint(sunsky.config_z[3]), __float_as_uint(sunsky.config_z[4])); - compiler.add_node(__float_as_uint(sunsky.config_z[5]), __float_as_uint(sunsky.config_z[6]), __float_as_uint(sunsky.config_z[7]), __float_as_uint(sunsky.config_z[8])); - - tex_mapping.compile_end(compiler, vector_in, vector_offset); -} - -void SkyTextureNode::compile(OSLCompiler& compiler) -{ - tex_mapping.compile(compiler); - - SunSky sunsky; - if(type == NODE_SKY_OLD) - sky_texture_precompute_old(&sunsky, sun_direction, turbidity); - else if(type == NODE_SKY_NEW) - sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); - else - assert(false); - - compiler.parameter(this, "type"); - compiler.parameter("theta", sunsky.theta); - compiler.parameter("phi", sunsky.phi); - compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z)); - compiler.parameter_array("config_x", sunsky.config_x, 9); - compiler.parameter_array("config_y", sunsky.config_y, 9); - compiler.parameter_array("config_z", sunsky.config_z, 9); - compiler.add(this, "node_sky_texture"); + NodeType *type = NodeType::add("sky_texture", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(SkyTextureNode); + + static NodeEnum type_enum; + type_enum.insert("preetham", NODE_SKY_OLD); + type_enum.insert("hosek_wilkie", NODE_SKY_NEW); + SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW); + + SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f)); + SOCKET_FLOAT(turbidity, "Turbidity", 2.2f); + SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f); + + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + + SOCKET_OUT_COLOR(color, "Color"); + + return type; +} + +SkyTextureNode::SkyTextureNode() : TextureNode(node_type) +{ +} + +void SkyTextureNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + + SunSky sunsky; + if (type == NODE_SKY_OLD) + sky_texture_precompute_old(&sunsky, sun_direction, turbidity); + else if (type == NODE_SKY_NEW) + sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); + else + assert(false); + + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + + compiler.stack_assign(color_out); + compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type); + compiler.add_node(__float_as_uint(sunsky.phi), + __float_as_uint(sunsky.theta), + __float_as_uint(sunsky.radiance_x), + __float_as_uint(sunsky.radiance_y)); + compiler.add_node(__float_as_uint(sunsky.radiance_z), + __float_as_uint(sunsky.config_x[0]), + __float_as_uint(sunsky.config_x[1]), + __float_as_uint(sunsky.config_x[2])); + compiler.add_node(__float_as_uint(sunsky.config_x[3]), + __float_as_uint(sunsky.config_x[4]), + __float_as_uint(sunsky.config_x[5]), + __float_as_uint(sunsky.config_x[6])); + compiler.add_node(__float_as_uint(sunsky.config_x[7]), + __float_as_uint(sunsky.config_x[8]), + __float_as_uint(sunsky.config_y[0]), + __float_as_uint(sunsky.config_y[1])); + compiler.add_node(__float_as_uint(sunsky.config_y[2]), + __float_as_uint(sunsky.config_y[3]), + __float_as_uint(sunsky.config_y[4]), + __float_as_uint(sunsky.config_y[5])); + compiler.add_node(__float_as_uint(sunsky.config_y[6]), + __float_as_uint(sunsky.config_y[7]), + __float_as_uint(sunsky.config_y[8]), + __float_as_uint(sunsky.config_z[0])); + compiler.add_node(__float_as_uint(sunsky.config_z[1]), + __float_as_uint(sunsky.config_z[2]), + __float_as_uint(sunsky.config_z[3]), + __float_as_uint(sunsky.config_z[4])); + compiler.add_node(__float_as_uint(sunsky.config_z[5]), + __float_as_uint(sunsky.config_z[6]), + __float_as_uint(sunsky.config_z[7]), + __float_as_uint(sunsky.config_z[8])); + + tex_mapping.compile_end(compiler, vector_in, vector_offset); +} + +void SkyTextureNode::compile(OSLCompiler &compiler) +{ + tex_mapping.compile(compiler); + + SunSky sunsky; + if (type == NODE_SKY_OLD) + sky_texture_precompute_old(&sunsky, sun_direction, turbidity); + else if (type == NODE_SKY_NEW) + sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo); + else + assert(false); + + compiler.parameter(this, "type"); + compiler.parameter("theta", sunsky.theta); + compiler.parameter("phi", sunsky.phi); + compiler.parameter_color("radiance", + make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z)); + compiler.parameter_array("config_x", sunsky.config_x, 9); + compiler.parameter_array("config_y", sunsky.config_y, 9); + compiler.parameter_array("config_z", sunsky.config_z, 9); + compiler.add(this, "node_sky_texture"); } /* Gradient Texture */ NODE_DEFINE(GradientTextureNode) { - NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("gradient_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(GradientTextureNode); + TEXTURE_MAPPING_DEFINE(GradientTextureNode); - static NodeEnum type_enum; - type_enum.insert("linear", NODE_BLEND_LINEAR); - type_enum.insert("quadratic", NODE_BLEND_QUADRATIC); - type_enum.insert("easing", NODE_BLEND_EASING); - type_enum.insert("diagonal", NODE_BLEND_DIAGONAL); - type_enum.insert("radial", NODE_BLEND_RADIAL); - type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE); - type_enum.insert("spherical", NODE_BLEND_SPHERICAL); - SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR); + static NodeEnum type_enum; + type_enum.insert("linear", NODE_BLEND_LINEAR); + type_enum.insert("quadratic", NODE_BLEND_QUADRATIC); + type_enum.insert("easing", NODE_BLEND_EASING); + type_enum.insert("diagonal", NODE_BLEND_DIAGONAL); + type_enum.insert("radial", NODE_BLEND_RADIAL); + type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE); + type_enum.insert("spherical", NODE_BLEND_SPHERICAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -GradientTextureNode::GradientTextureNode() -: TextureNode(node_type) +GradientTextureNode::GradientTextureNode() : TextureNode(node_type) { } -void GradientTextureNode::compile(SVMCompiler& compiler) +void GradientTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *fac_out = output("Fac"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_GRADIENT, - compiler.encode_uchar4( - type, - vector_offset, - compiler.stack_assign_if_linked(fac_out), - compiler.stack_assign_if_linked(color_out))); + compiler.add_node(NODE_TEX_GRADIENT, + compiler.encode_uchar4(type, + vector_offset, + compiler.stack_assign_if_linked(fac_out), + compiler.stack_assign_if_linked(color_out))); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void GradientTextureNode::compile(OSLCompiler& compiler) +void GradientTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter(this, "type"); - compiler.add(this, "node_gradient_texture"); + compiler.parameter(this, "type"); + compiler.add(this, "node_gradient_texture"); } /* Noise Texture */ NODE_DEFINE(NoiseTextureNode) { - NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("noise_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(NoiseTextureNode); + TEXTURE_MAPPING_DEFINE(NoiseTextureNode); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_IN_FLOAT(detail, "Detail", 2.0f); - SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -NoiseTextureNode::NoiseTextureNode() -: TextureNode(node_type) +NoiseTextureNode::NoiseTextureNode() : TextureNode(node_type) { } -void NoiseTextureNode::compile(SVMCompiler& compiler) +void NoiseTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *distortion_in = input("Distortion"); - ShaderInput *detail_in = input("Detail"); - ShaderInput *scale_in = input("Scale"); - ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *fac_out = output("Fac"); + ShaderInput *distortion_in = input("Distortion"); + ShaderInput *detail_in = input("Detail"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_NOISE, - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(detail_in), - compiler.stack_assign_if_linked(distortion_in)), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out))); - compiler.add_node( - __float_as_int(scale), - __float_as_int(detail), - __float_as_int(distortion)); + compiler.add_node(NODE_TEX_NOISE, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(scale_in), + compiler.stack_assign_if_linked(detail_in), + compiler.stack_assign_if_linked(distortion_in)), + compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(fac_out))); + compiler.add_node(__float_as_int(scale), __float_as_int(detail), __float_as_int(distortion)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void NoiseTextureNode::compile(OSLCompiler& compiler) +void NoiseTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.add(this, "node_noise_texture"); + compiler.add(this, "node_noise_texture"); } /* Voronoi Texture */ NODE_DEFINE(VoronoiTextureNode) { - NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("voronoi_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(VoronoiTextureNode); + TEXTURE_MAPPING_DEFINE(VoronoiTextureNode); - static NodeEnum coloring_enum; - coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY); - coloring_enum.insert("cells", NODE_VORONOI_CELLS); - SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY); + static NodeEnum coloring_enum; + coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY); + coloring_enum.insert("cells", NODE_VORONOI_CELLS); + SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY); - static NodeEnum metric; - metric.insert("distance", NODE_VORONOI_DISTANCE); - metric.insert("manhattan", NODE_VORONOI_MANHATTAN); - metric.insert("chebychev", NODE_VORONOI_CHEBYCHEV); - metric.insert("minkowski", NODE_VORONOI_MINKOWSKI); - SOCKET_ENUM(metric, "Distance Metric", metric, NODE_VORONOI_INTENSITY); + static NodeEnum metric; + metric.insert("distance", NODE_VORONOI_DISTANCE); + metric.insert("manhattan", NODE_VORONOI_MANHATTAN); + metric.insert("chebychev", NODE_VORONOI_CHEBYCHEV); + metric.insert("minkowski", NODE_VORONOI_MINKOWSKI); + SOCKET_ENUM(metric, "Distance Metric", metric, NODE_VORONOI_INTENSITY); - static NodeEnum feature_enum; - feature_enum.insert("F1", NODE_VORONOI_F1); - feature_enum.insert("F2", NODE_VORONOI_F2); - feature_enum.insert("F3", NODE_VORONOI_F3); - feature_enum.insert("F4", NODE_VORONOI_F4); - feature_enum.insert("F2F1", NODE_VORONOI_F2F1); - SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_INTENSITY); + static NodeEnum feature_enum; + feature_enum.insert("F1", NODE_VORONOI_F1); + feature_enum.insert("F2", NODE_VORONOI_F2); + feature_enum.insert("F3", NODE_VORONOI_F3); + feature_enum.insert("F4", NODE_VORONOI_F4); + feature_enum.insert("F2F1", NODE_VORONOI_F2F1); + SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_INTENSITY); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -VoronoiTextureNode::VoronoiTextureNode() -: TextureNode(node_type) +VoronoiTextureNode::VoronoiTextureNode() : TextureNode(node_type) { } -void VoronoiTextureNode::compile(SVMCompiler& compiler) +void VoronoiTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *scale_in = input("Scale"); - ShaderInput *vector_in = input("Vector"); - ShaderInput *exponent_in = input("Exponent"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *fac_out = output("Fac"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *vector_in = input("Vector"); + ShaderInput *exponent_in = input("Exponent"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); - if(vector_in->link) compiler.stack_assign(vector_in); - if(scale_in->link) compiler.stack_assign(scale_in); - if(exponent_in->link) compiler.stack_assign(exponent_in); + if (vector_in->link) + compiler.stack_assign(vector_in); + if (scale_in->link) + compiler.stack_assign(scale_in); + if (exponent_in->link) + compiler.stack_assign(exponent_in); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_VORONOI, - compiler.encode_uchar4( - vector_offset, - coloring, - metric, - feature - ), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(exponent_in), - compiler.stack_assign(fac_out), - compiler.stack_assign(color_out) - )); - compiler.add_node( - __float_as_int(scale), - __float_as_int(exponent)); + compiler.add_node(NODE_TEX_VORONOI, + compiler.encode_uchar4(vector_offset, coloring, metric, feature), + compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in), + compiler.stack_assign_if_linked(exponent_in), + compiler.stack_assign(fac_out), + compiler.stack_assign(color_out))); + compiler.add_node(__float_as_int(scale), __float_as_int(exponent)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void VoronoiTextureNode::compile(OSLCompiler& compiler) +void VoronoiTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter(this, "coloring"); - compiler.parameter(this, "metric"); - compiler.parameter(this, "feature"); - compiler.add(this, "node_voronoi_texture"); + compiler.parameter(this, "coloring"); + compiler.parameter(this, "metric"); + compiler.parameter(this, "feature"); + compiler.add(this, "node_voronoi_texture"); } /* IES Light */ NODE_DEFINE(IESLightNode) { - NodeType* type = NodeType::add("ies_light", create, NodeType::SHADER); + NodeType *type = NodeType::add("ies_light", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(IESLightNode); + TEXTURE_MAPPING_DEFINE(IESLightNode); - SOCKET_STRING(ies, "IES", ustring()); - SOCKET_STRING(filename, "File Name", ustring()); + SOCKET_STRING(ies, "IES", ustring()); + SOCKET_STRING(filename, "File Name", ustring()); - SOCKET_IN_FLOAT(strength, "Strength", 1.0f); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_NORMAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_NORMAL); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -IESLightNode::IESLightNode() -: TextureNode(node_type) +IESLightNode::IESLightNode() : TextureNode(node_type) { - light_manager = NULL; - slot = -1; + light_manager = NULL; + slot = -1; } ShaderNode *IESLightNode::clone() const { - IESLightNode *node = new IESLightNode(*this); + IESLightNode *node = new IESLightNode(*this); - node->light_manager = NULL; - node->slot = -1; + node->light_manager = NULL; + node->slot = -1; - return node; + return node; } IESLightNode::~IESLightNode() { - if(light_manager) { - light_manager->remove_ies(slot); - } + if (light_manager) { + light_manager->remove_ies(slot); + } } void IESLightNode::get_slot() { - assert(light_manager); + assert(light_manager); - if(slot == -1) { - if(ies.empty()) { - slot = light_manager->add_ies_from_file(filename); - } - else { - slot = light_manager->add_ies(ies); - } - } + if (slot == -1) { + if (ies.empty()) { + slot = light_manager->add_ies_from_file(filename); + } + else { + slot = light_manager->add_ies(ies); + } + } } -void IESLightNode::compile(SVMCompiler& compiler) +void IESLightNode::compile(SVMCompiler &compiler) { - light_manager = compiler.light_manager; - get_slot(); + light_manager = compiler.light_manager; + get_slot(); - ShaderInput *strength_in = input("Strength"); - ShaderInput *vector_in = input("Vector"); - ShaderOutput *fac_out = output("Fac"); + ShaderInput *strength_in = input("Strength"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_IES, - compiler.encode_uchar4( - compiler.stack_assign_if_linked(strength_in), - vector_offset, - compiler.stack_assign(fac_out), - 0), - slot, - __float_as_int(strength)); + compiler.add_node(NODE_IES, + compiler.encode_uchar4(compiler.stack_assign_if_linked(strength_in), + vector_offset, + compiler.stack_assign(fac_out), + 0), + slot, + __float_as_int(strength)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void IESLightNode::compile(OSLCompiler& compiler) +void IESLightNode::compile(OSLCompiler &compiler) { - light_manager = compiler.light_manager; - get_slot(); + light_manager = compiler.light_manager; + get_slot(); - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter("slot", slot); - compiler.add(this, "node_ies_light"); + compiler.parameter("slot", slot); + compiler.add(this, "node_ies_light"); } /* Musgrave Texture */ NODE_DEFINE(MusgraveTextureNode) { - NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("musgrave_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(MusgraveTextureNode); + TEXTURE_MAPPING_DEFINE(MusgraveTextureNode); - static NodeEnum type_enum; - type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL); - type_enum.insert("fBM", NODE_MUSGRAVE_FBM); - type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); - type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); - type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN); - SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM); + static NodeEnum type_enum; + type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL); + type_enum.insert("fBM", NODE_MUSGRAVE_FBM); + type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); + type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); + type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN); + SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_IN_FLOAT(detail, "Detail", 2.0f); - SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f); - SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f); - SOCKET_IN_FLOAT(offset, "Offset", 0.0f); - SOCKET_IN_FLOAT(gain, "Gain", 1.0f); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f); + SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f); + SOCKET_IN_FLOAT(offset, "Offset", 0.0f); + SOCKET_IN_FLOAT(gain, "Gain", 1.0f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -MusgraveTextureNode::MusgraveTextureNode() -: TextureNode(node_type) +MusgraveTextureNode::MusgraveTextureNode() : TextureNode(node_type) { } -void MusgraveTextureNode::compile(SVMCompiler& compiler) +void MusgraveTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderInput *scale_in = input("Scale"); - ShaderInput *dimension_in = input("Dimension"); - ShaderInput *lacunarity_in = input("Lacunarity"); - ShaderInput *detail_in = input("Detail"); - ShaderInput *offset_in = input("Offset"); - ShaderInput *gain_in = input("Gain"); - ShaderOutput *fac_out = output("Fac"); - ShaderOutput *color_out = output("Color"); + ShaderInput *vector_in = input("Vector"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *dimension_in = input("Dimension"); + ShaderInput *lacunarity_in = input("Lacunarity"); + ShaderInput *detail_in = input("Detail"); + ShaderInput *offset_in = input("Offset"); + ShaderInput *gain_in = input("Gain"); + ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_MUSGRAVE, - compiler.encode_uchar4( - type, - vector_offset, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out)), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(dimension_in), - compiler.stack_assign_if_linked(lacunarity_in), - compiler.stack_assign_if_linked(detail_in), - compiler.stack_assign_if_linked(offset_in)), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(gain_in), - compiler.stack_assign_if_linked(scale_in))); - compiler.add_node(__float_as_int(dimension), - __float_as_int(lacunarity), - __float_as_int(detail), - __float_as_int(offset)); - compiler.add_node(__float_as_int(gain), - __float_as_int(scale)); + compiler.add_node(NODE_TEX_MUSGRAVE, + compiler.encode_uchar4(type, + vector_offset, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(fac_out)), + compiler.encode_uchar4(compiler.stack_assign_if_linked(dimension_in), + compiler.stack_assign_if_linked(lacunarity_in), + compiler.stack_assign_if_linked(detail_in), + compiler.stack_assign_if_linked(offset_in)), + compiler.encode_uchar4(compiler.stack_assign_if_linked(gain_in), + compiler.stack_assign_if_linked(scale_in))); + compiler.add_node(__float_as_int(dimension), + __float_as_int(lacunarity), + __float_as_int(detail), + __float_as_int(offset)); + compiler.add_node(__float_as_int(gain), __float_as_int(scale)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void MusgraveTextureNode::compile(OSLCompiler& compiler) +void MusgraveTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter(this, "type"); - compiler.add(this, "node_musgrave_texture"); + compiler.parameter(this, "type"); + compiler.add(this, "node_musgrave_texture"); } /* Wave Texture */ NODE_DEFINE(WaveTextureNode) { - NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("wave_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(WaveTextureNode); + TEXTURE_MAPPING_DEFINE(WaveTextureNode); - static NodeEnum type_enum; - type_enum.insert("bands", NODE_WAVE_BANDS); - type_enum.insert("rings", NODE_WAVE_RINGS); - SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS); + static NodeEnum type_enum; + type_enum.insert("bands", NODE_WAVE_BANDS); + type_enum.insert("rings", NODE_WAVE_RINGS); + SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS); - static NodeEnum profile_enum; - profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN); - profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW); - SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN); + static NodeEnum profile_enum; + profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN); + profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW); + SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); - SOCKET_IN_FLOAT(detail, "Detail", 2.0f); - SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); + SOCKET_IN_FLOAT(detail, "Detail", 2.0f); + SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -WaveTextureNode::WaveTextureNode() -: TextureNode(node_type) +WaveTextureNode::WaveTextureNode() : TextureNode(node_type) { } -void WaveTextureNode::compile(SVMCompiler& compiler) +void WaveTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *scale_in = input("Scale"); - ShaderInput *distortion_in = input("Distortion"); - ShaderInput *dscale_in = input("Detail Scale"); - ShaderInput *detail_in = input("Detail"); - ShaderInput *vector_in = input("Vector"); - ShaderOutput *fac_out = output("Fac"); - ShaderOutput *color_out = output("Color"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *distortion_in = input("Distortion"); + ShaderInput *dscale_in = input("Detail Scale"); + ShaderInput *detail_in = input("Detail"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_WAVE, - compiler.encode_uchar4( - type, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out), - compiler.stack_assign_if_linked(dscale_in)), - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(detail_in), - compiler.stack_assign_if_linked(distortion_in)), - profile); + compiler.add_node(NODE_TEX_WAVE, + compiler.encode_uchar4(type, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(fac_out), + compiler.stack_assign_if_linked(dscale_in)), + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(scale_in), + compiler.stack_assign_if_linked(detail_in), + compiler.stack_assign_if_linked(distortion_in)), + profile); - compiler.add_node( - __float_as_int(scale), - __float_as_int(detail), - __float_as_int(distortion), - __float_as_int(detail_scale)); + compiler.add_node(__float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion), + __float_as_int(detail_scale)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void WaveTextureNode::compile(OSLCompiler& compiler) +void WaveTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter(this, "type"); - compiler.parameter(this, "profile"); + compiler.parameter(this, "type"); + compiler.parameter(this, "profile"); - compiler.add(this, "node_wave_texture"); + compiler.add(this, "node_wave_texture"); } /* Magic Texture */ NODE_DEFINE(MagicTextureNode) { - NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("magic_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(MagicTextureNode); + TEXTURE_MAPPING_DEFINE(MagicTextureNode); - SOCKET_INT(depth, "Depth", 2); + SOCKET_INT(depth, "Depth", 2); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_IN_FLOAT(scale, "Scale", 5.0f); - SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(scale, "Scale", 5.0f); + SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -MagicTextureNode::MagicTextureNode() -: TextureNode(node_type) +MagicTextureNode::MagicTextureNode() : TextureNode(node_type) { } -void MagicTextureNode::compile(SVMCompiler& compiler) +void MagicTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderInput *scale_in = input("Scale"); - ShaderInput *distortion_in = input("Distortion"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *fac_out = output("Fac"); + ShaderInput *vector_in = input("Vector"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *distortion_in = input("Distortion"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_MAGIC, - compiler.encode_uchar4( - depth, - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out)), - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(distortion_in))); - compiler.add_node( - __float_as_int(scale), - __float_as_int(distortion)); + compiler.add_node(NODE_TEX_MAGIC, + compiler.encode_uchar4(depth, + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(fac_out)), + compiler.encode_uchar4(vector_offset, + compiler.stack_assign_if_linked(scale_in), + compiler.stack_assign_if_linked(distortion_in))); + compiler.add_node(__float_as_int(scale), __float_as_int(distortion)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void MagicTextureNode::compile(OSLCompiler& compiler) +void MagicTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter(this, "depth"); - compiler.add(this, "node_magic_texture"); + compiler.parameter(this, "depth"); + compiler.add(this, "node_magic_texture"); } /* Checker Texture */ NODE_DEFINE(CheckerTextureNode) { - NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("checker_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(CheckerTextureNode); + TEXTURE_MAPPING_DEFINE(CheckerTextureNode); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -CheckerTextureNode::CheckerTextureNode() -: TextureNode(node_type) +CheckerTextureNode::CheckerTextureNode() : TextureNode(node_type) { } -void CheckerTextureNode::compile(SVMCompiler& compiler) +void CheckerTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderInput *color1_in = input("Color1"); - ShaderInput *color2_in = input("Color2"); - ShaderInput *scale_in = input("Scale"); + ShaderInput *vector_in = input("Vector"); + ShaderInput *color1_in = input("Color1"); + ShaderInput *color2_in = input("Color2"); + ShaderInput *scale_in = input("Scale"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_CHECKER, - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign(color1_in), - compiler.stack_assign(color2_in), - compiler.stack_assign_if_linked(scale_in)), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out)), - __float_as_int(scale)); + compiler.add_node(NODE_TEX_CHECKER, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign(color1_in), + compiler.stack_assign(color2_in), + compiler.stack_assign_if_linked(scale_in)), + compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(fac_out)), + __float_as_int(scale)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void CheckerTextureNode::compile(OSLCompiler& compiler) +void CheckerTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.add(this, "node_checker_texture"); + compiler.add(this, "node_checker_texture"); } /* Brick Texture */ NODE_DEFINE(BrickTextureNode) { - NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("brick_texture", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(BrickTextureNode); + TEXTURE_MAPPING_DEFINE(BrickTextureNode); - SOCKET_FLOAT(offset, "Offset", 0.5f); - SOCKET_INT(offset_frequency, "Offset Frequency", 2); - SOCKET_FLOAT(squash, "Squash", 1.0f); - SOCKET_INT(squash_frequency, "Squash Frequency", 2); + SOCKET_FLOAT(offset, "Offset", 0.5f); + SOCKET_INT(offset_frequency, "Offset Frequency", 2); + SOCKET_FLOAT(squash, "Squash", 1.0f); + SOCKET_INT(squash_frequency, "Squash Frequency", 2); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_FLOAT(scale, "Scale", 5.0f); - SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f); - SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f); - SOCKET_IN_FLOAT(bias, "Bias", 0.0f); - SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f); - SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(scale, "Scale", 5.0f); + SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f); + SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f); + SOCKET_IN_FLOAT(bias, "Bias", 0.0f); + SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f); + SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -BrickTextureNode::BrickTextureNode() -: TextureNode(node_type) +BrickTextureNode::BrickTextureNode() : TextureNode(node_type) { } -void BrickTextureNode::compile(SVMCompiler& compiler) +void BrickTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderInput *color1_in = input("Color1"); - ShaderInput *color2_in = input("Color2"); - ShaderInput *mortar_in = input("Mortar"); - ShaderInput *scale_in = input("Scale"); - ShaderInput *mortar_size_in = input("Mortar Size"); - ShaderInput *mortar_smooth_in = input("Mortar Smooth"); - ShaderInput *bias_in = input("Bias"); - ShaderInput *brick_width_in = input("Brick Width"); - ShaderInput *row_height_in = input("Row Height"); + ShaderInput *vector_in = input("Vector"); + ShaderInput *color1_in = input("Color1"); + ShaderInput *color2_in = input("Color2"); + ShaderInput *mortar_in = input("Mortar"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *mortar_size_in = input("Mortar Size"); + ShaderInput *mortar_smooth_in = input("Mortar Smooth"); + ShaderInput *bias_in = input("Bias"); + ShaderInput *brick_width_in = input("Brick Width"); + ShaderInput *row_height_in = input("Row Height"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); - compiler.add_node(NODE_TEX_BRICK, - compiler.encode_uchar4( - vector_offset, - compiler.stack_assign(color1_in), - compiler.stack_assign(color2_in), - compiler.stack_assign(mortar_in)), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(mortar_size_in), - compiler.stack_assign_if_linked(bias_in), - compiler.stack_assign_if_linked(brick_width_in)), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(row_height_in), - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out), - compiler.stack_assign_if_linked(mortar_smooth_in))); + compiler.add_node(NODE_TEX_BRICK, + compiler.encode_uchar4(vector_offset, + compiler.stack_assign(color1_in), + compiler.stack_assign(color2_in), + compiler.stack_assign(mortar_in)), + compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in), + compiler.stack_assign_if_linked(mortar_size_in), + compiler.stack_assign_if_linked(bias_in), + compiler.stack_assign_if_linked(brick_width_in)), + compiler.encode_uchar4(compiler.stack_assign_if_linked(row_height_in), + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(fac_out), + compiler.stack_assign_if_linked(mortar_smooth_in))); - compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), - __float_as_int(scale), - __float_as_int(mortar_size), - __float_as_int(bias)); + compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), + __float_as_int(scale), + __float_as_int(mortar_size), + __float_as_int(bias)); - compiler.add_node(__float_as_int(brick_width), - __float_as_int(row_height), - __float_as_int(offset), - __float_as_int(squash)); + compiler.add_node(__float_as_int(brick_width), + __float_as_int(row_height), + __float_as_int(offset), + __float_as_int(squash)); - compiler.add_node(__float_as_int(mortar_smooth), - SVM_STACK_INVALID, - SVM_STACK_INVALID, - SVM_STACK_INVALID); + compiler.add_node( + __float_as_int(mortar_smooth), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } -void BrickTextureNode::compile(OSLCompiler& compiler) +void BrickTextureNode::compile(OSLCompiler &compiler) { - tex_mapping.compile(compiler); + tex_mapping.compile(compiler); - compiler.parameter(this, "offset"); - compiler.parameter(this, "offset_frequency"); - compiler.parameter(this, "squash"); - compiler.parameter(this, "squash_frequency"); - compiler.add(this, "node_brick_texture"); + compiler.parameter(this, "offset"); + compiler.parameter(this, "offset_frequency"); + compiler.parameter(this, "squash"); + compiler.parameter(this, "squash_frequency"); + compiler.add(this, "node_brick_texture"); } /* Point Density Texture */ NODE_DEFINE(PointDensityTextureNode) { - NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER); + NodeType *type = NodeType::add("point_density_texture", create, NodeType::SHADER); - SOCKET_STRING(filename, "Filename", ustring()); + SOCKET_STRING(filename, "Filename", ustring()); - static NodeEnum space_enum; - space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT); - space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD); - SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT); + static NodeEnum space_enum; + space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT); + space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD); + SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT); - static NodeEnum interpolation_enum; - interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); - interpolation_enum.insert("linear", INTERPOLATION_LINEAR); - interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); - interpolation_enum.insert("smart", INTERPOLATION_SMART); - SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); + static NodeEnum interpolation_enum; + interpolation_enum.insert("closest", INTERPOLATION_CLOSEST); + interpolation_enum.insert("linear", INTERPOLATION_LINEAR); + interpolation_enum.insert("cubic", INTERPOLATION_CUBIC); + interpolation_enum.insert("smart", INTERPOLATION_SMART); + SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR); - SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION); - SOCKET_OUT_FLOAT(density, "Density"); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(density, "Density"); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -PointDensityTextureNode::PointDensityTextureNode() -: ShaderNode(node_type) +PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(node_type) { - image_manager = NULL; - slot = -1; - builtin_data = NULL; + image_manager = NULL; + slot = -1; + builtin_data = NULL; } PointDensityTextureNode::~PointDensityTextureNode() { - if(image_manager) { - image_manager->remove_image(filename.string(), - builtin_data, - interpolation, - EXTENSION_CLIP, - true); - } + if (image_manager) { + image_manager->remove_image( + filename.string(), builtin_data, interpolation, EXTENSION_CLIP, true); + } } ShaderNode *PointDensityTextureNode::clone() const { - PointDensityTextureNode *node = new PointDensityTextureNode(*this); - node->image_manager = NULL; - node->slot = -1; - return node; + PointDensityTextureNode *node = new PointDensityTextureNode(*this); + node->image_manager = NULL; + node->slot = -1; + return node; } -void PointDensityTextureNode::attributes(Shader *shader, - AttributeRequestSet *attributes) +void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_volume) - attributes->add(ATTR_STD_GENERATED_TRANSFORM); + if (shader->has_volume) + attributes->add(ATTR_STD_GENERATED_TRANSFORM); - ShaderNode::attributes(shader, attributes); + ShaderNode::attributes(shader, attributes); } void PointDensityTextureNode::add_image() { - if(slot == -1) { - ImageMetaData metadata; - slot = image_manager->add_image(filename.string(), builtin_data, - false, 0, - interpolation, - EXTENSION_CLIP, - true, - metadata); - } -} - -void PointDensityTextureNode::compile(SVMCompiler& compiler) -{ - ShaderInput *vector_in = input("Vector"); - ShaderOutput *density_out = output("Density"); - ShaderOutput *color_out = output("Color"); - - const bool use_density = !density_out->links.empty(); - const bool use_color = !color_out->links.empty(); - - image_manager = compiler.image_manager; - - if(use_density || use_color) { - add_image(); - - if(slot != -1) { - compiler.stack_assign(vector_in); - compiler.add_node(NODE_TEX_VOXEL, - slot, - compiler.encode_uchar4(compiler.stack_assign(vector_in), - compiler.stack_assign_if_linked(density_out), - compiler.stack_assign_if_linked(color_out), - space)); - if(space == NODE_TEX_VOXEL_SPACE_WORLD) { - compiler.add_node(tfm.x); - compiler.add_node(tfm.y); - compiler.add_node(tfm.z); - } - } - else { - if(use_density) { - compiler.add_node(NODE_VALUE_F, - __float_as_int(0.0f), - compiler.stack_assign(density_out)); - } - if(use_color) { - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); - compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R, - TEX_IMAGE_MISSING_G, - TEX_IMAGE_MISSING_B)); - } - } - } -} - -void PointDensityTextureNode::compile(OSLCompiler& compiler) -{ - ShaderOutput *density_out = output("Density"); - ShaderOutput *color_out = output("Color"); - - const bool use_density = !density_out->links.empty(); - const bool use_color = !color_out->links.empty(); - - image_manager = compiler.image_manager; - - if(use_density || use_color) { - add_image(); - - if(slot != -1) { - compiler.parameter("filename", string_printf("@i%d", slot).c_str()); - } - if(space == NODE_TEX_VOXEL_SPACE_WORLD) { - compiler.parameter("mapping", tfm); - compiler.parameter("use_mapping", 1); - } - compiler.parameter(this, "interpolation"); - compiler.add(this, "node_voxel_texture"); - } + if (slot == -1) { + ImageMetaData metadata; + slot = image_manager->add_image( + filename.string(), builtin_data, false, 0, interpolation, EXTENSION_CLIP, true, metadata); + } +} + +void PointDensityTextureNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *density_out = output("Density"); + ShaderOutput *color_out = output("Color"); + + const bool use_density = !density_out->links.empty(); + const bool use_color = !color_out->links.empty(); + + image_manager = compiler.image_manager; + + if (use_density || use_color) { + add_image(); + + if (slot != -1) { + compiler.stack_assign(vector_in); + compiler.add_node(NODE_TEX_VOXEL, + slot, + compiler.encode_uchar4(compiler.stack_assign(vector_in), + compiler.stack_assign_if_linked(density_out), + compiler.stack_assign_if_linked(color_out), + space)); + if (space == NODE_TEX_VOXEL_SPACE_WORLD) { + compiler.add_node(tfm.x); + compiler.add_node(tfm.y); + compiler.add_node(tfm.z); + } + } + else { + if (use_density) { + compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(density_out)); + } + if (use_color) { + compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); + compiler.add_node( + NODE_VALUE_V, + make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B)); + } + } + } +} + +void PointDensityTextureNode::compile(OSLCompiler &compiler) +{ + ShaderOutput *density_out = output("Density"); + ShaderOutput *color_out = output("Color"); + + const bool use_density = !density_out->links.empty(); + const bool use_color = !color_out->links.empty(); + + image_manager = compiler.image_manager; + + if (use_density || use_color) { + add_image(); + + if (slot != -1) { + compiler.parameter("filename", string_printf("@i%d", slot).c_str()); + } + if (space == NODE_TEX_VOXEL_SPACE_WORLD) { + compiler.parameter("mapping", tfm); + compiler.parameter("use_mapping", 1); + } + compiler.parameter(this, "interpolation"); + compiler.add(this, "node_voxel_texture"); + } } /* Normal */ NODE_DEFINE(NormalNode) { - NodeType* type = NodeType::add("normal", create, NodeType::SHADER); + NodeType *type = NodeType::add("normal", create, NodeType::SHADER); - SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_NORMAL(normal, "Normal"); - SOCKET_OUT_FLOAT(dot, "Dot"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_FLOAT(dot, "Dot"); - return type; + return type; } -NormalNode::NormalNode() -: ShaderNode(node_type) +NormalNode::NormalNode() : ShaderNode(node_type) { } -void NormalNode::compile(SVMCompiler& compiler) +void NormalNode::compile(SVMCompiler &compiler) { - ShaderInput *normal_in = input("Normal"); - ShaderOutput *normal_out = output("Normal"); - ShaderOutput *dot_out = output("Dot"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *normal_out = output("Normal"); + ShaderOutput *dot_out = output("Dot"); - compiler.add_node(NODE_NORMAL, - compiler.stack_assign(normal_in), - compiler.stack_assign(normal_out), - compiler.stack_assign(dot_out)); - compiler.add_node( - __float_as_int(direction.x), - __float_as_int(direction.y), - __float_as_int(direction.z)); + compiler.add_node(NODE_NORMAL, + compiler.stack_assign(normal_in), + compiler.stack_assign(normal_out), + compiler.stack_assign(dot_out)); + compiler.add_node( + __float_as_int(direction.x), __float_as_int(direction.y), __float_as_int(direction.z)); } -void NormalNode::compile(OSLCompiler& compiler) +void NormalNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "direction"); - compiler.add(this, "node_normal"); + compiler.parameter(this, "direction"); + compiler.add(this, "node_normal"); } /* Mapping */ NODE_DEFINE(MappingNode) { - NodeType* type = NodeType::add("mapping", create, NodeType::SHADER); + NodeType *type = NodeType::add("mapping", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(MappingNode); + TEXTURE_MAPPING_DEFINE(MappingNode); - SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_POINT(vector, "Vector"); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_POINT(vector, "Vector"); - return type; + return type; } -MappingNode::MappingNode() -: ShaderNode(node_type) +MappingNode::MappingNode() : ShaderNode(node_type) { } -void MappingNode::compile(SVMCompiler& compiler) +void MappingNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderOutput *vector_out = output("Vector"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *vector_out = output("Vector"); - tex_mapping.compile(compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)); + tex_mapping.compile( + compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)); } -void MappingNode::compile(OSLCompiler& compiler) +void MappingNode::compile(OSLCompiler &compiler) { - compiler.parameter("Matrix", tex_mapping.compute_transform()); - compiler.parameter_point("mapping_min", tex_mapping.min); - compiler.parameter_point("mapping_max", tex_mapping.max); - compiler.parameter("use_minmax", tex_mapping.use_minmax); + compiler.parameter("Matrix", tex_mapping.compute_transform()); + compiler.parameter_point("mapping_min", tex_mapping.min); + compiler.parameter_point("mapping_max", tex_mapping.max); + compiler.parameter("use_minmax", tex_mapping.use_minmax); - compiler.add(this, "node_mapping"); + compiler.add(this, "node_mapping"); } /* RGBToBW */ NODE_DEFINE(RGBToBWNode) { - NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER); + NodeType *type = NodeType::add("rgb_to_bw", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_FLOAT(val, "Val"); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_FLOAT(val, "Val"); - return type; + return type; } -RGBToBWNode::RGBToBWNode() -: ShaderNode(node_type) +RGBToBWNode::RGBToBWNode() : ShaderNode(node_type) { } -void RGBToBWNode::constant_fold(const ConstantFolder& folder) +void RGBToBWNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - float val = folder.scene->shader_manager->linear_rgb_to_gray(color); - folder.make_constant(val); - } + if (folder.all_inputs_constant()) { + float val = folder.scene->shader_manager->linear_rgb_to_gray(color); + folder.make_constant(val); + } } -void RGBToBWNode::compile(SVMCompiler& compiler) +void RGBToBWNode::compile(SVMCompiler &compiler) { - compiler.add_node(NODE_CONVERT, - NODE_CONVERT_CF, - compiler.stack_assign(inputs[0]), - compiler.stack_assign(outputs[0])); + compiler.add_node(NODE_CONVERT, + NODE_CONVERT_CF, + compiler.stack_assign(inputs[0]), + compiler.stack_assign(outputs[0])); } -void RGBToBWNode::compile(OSLCompiler& compiler) +void RGBToBWNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_rgb_to_bw"); + compiler.add(this, "node_rgb_to_bw"); } /* Convert */ -const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE]; +const NodeType *ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE]; bool ConvertNode::initialized = ConvertNode::register_types(); -Node* ConvertNode::create(const NodeType *type) +Node *ConvertNode::create(const NodeType *type) { - return new ConvertNode(type->inputs[0].type, type->outputs[0].type); + return new ConvertNode(type->inputs[0].type, type->outputs[0].type); } bool ConvertNode::register_types() { - const int num_types = 8; - SocketType::Type types[num_types] = {SocketType::FLOAT, - SocketType::INT, - SocketType::COLOR, - SocketType::VECTOR, - SocketType::POINT, - SocketType::NORMAL, - SocketType::STRING, - SocketType::CLOSURE}; - - for(size_t i = 0; i < num_types; i++) { - SocketType::Type from = types[i]; - ustring from_name(SocketType::type_name(from)); - ustring from_value_name("value_" + from_name.string()); - - for(size_t j = 0; j < num_types; j++) { - SocketType::Type to = types[j]; - ustring to_name(SocketType::type_name(to)); - ustring to_value_name("value_" + to_name.string()); - - string node_name = "convert_" + from_name.string() + "_to_" + to_name.string(); - NodeType* type = NodeType::add(node_name.c_str(), create, NodeType::SHADER); - - type->register_input(from_value_name, from_value_name, from, - SOCKET_OFFSETOF(ConvertNode, value_float), SocketType::zero_default_value(), - NULL, NULL, SocketType::LINKABLE); - type->register_output(to_value_name, to_value_name, to); - - assert(from < MAX_TYPE); - assert(to < MAX_TYPE); - - node_types[from][to] = type; - } - } - - return true; + const int num_types = 8; + SocketType::Type types[num_types] = {SocketType::FLOAT, + SocketType::INT, + SocketType::COLOR, + SocketType::VECTOR, + SocketType::POINT, + SocketType::NORMAL, + SocketType::STRING, + SocketType::CLOSURE}; + + for (size_t i = 0; i < num_types; i++) { + SocketType::Type from = types[i]; + ustring from_name(SocketType::type_name(from)); + ustring from_value_name("value_" + from_name.string()); + + for (size_t j = 0; j < num_types; j++) { + SocketType::Type to = types[j]; + ustring to_name(SocketType::type_name(to)); + ustring to_value_name("value_" + to_name.string()); + + string node_name = "convert_" + from_name.string() + "_to_" + to_name.string(); + NodeType *type = NodeType::add(node_name.c_str(), create, NodeType::SHADER); + + type->register_input(from_value_name, + from_value_name, + from, + SOCKET_OFFSETOF(ConvertNode, value_float), + SocketType::zero_default_value(), + NULL, + NULL, + SocketType::LINKABLE); + type->register_output(to_value_name, to_value_name, to); + + assert(from < MAX_TYPE); + assert(to < MAX_TYPE); + + node_types[from][to] = type; + } + } + + return true; } ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert) -: ShaderNode(node_types[from_][to_]) -{ - from = from_; - to = to_; - - if(from == to) - special_type = SHADER_SPECIAL_TYPE_PROXY; - else if(autoconvert) - special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; -} - -void ConvertNode::constant_fold(const ConstantFolder& folder) -{ - /* proxy nodes should have been removed at this point */ - assert(special_type != SHADER_SPECIAL_TYPE_PROXY); - - /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ - - if(folder.all_inputs_constant()) { - if(from == SocketType::FLOAT) { - if(SocketType::is_float3(to)) { - folder.make_constant(make_float3(value_float, value_float, value_float)); - } - } - else if(SocketType::is_float3(from)) { - if(to == SocketType::FLOAT) { - if(from == SocketType::COLOR) { - /* color to float */ - float val = folder.scene->shader_manager->linear_rgb_to_gray(value_color); - folder.make_constant(val); - } - else { - /* vector/point/normal to float */ - folder.make_constant(average(value_vector)); - } - } - else if(SocketType::is_float3(to)) { - folder.make_constant(value_color); - } - } - } - else { - ShaderInput *in = inputs[0]; - ShaderNode *prev = in->link->parent; - - /* no-op conversion of A to B to A */ - if(prev->type == node_types[to][from]) { - ShaderInput *prev_in = prev->inputs[0]; - - if(SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) && prev_in->link) { - folder.bypass(prev_in->link); - } - } - } -} - -void ConvertNode::compile(SVMCompiler& compiler) -{ - /* proxy nodes should have been removed at this point */ - assert(special_type != SHADER_SPECIAL_TYPE_PROXY); - - ShaderInput *in = inputs[0]; - ShaderOutput *out = outputs[0]; - - if(from == SocketType::FLOAT) { - if(to == SocketType::INT) - /* float to int */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out)); - else - /* float to float3 */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out)); - } - else if(from == SocketType::INT) { - if(to == SocketType::FLOAT) - /* int to float */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out)); - else - /* int to vector/point/normal */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out)); - } - else if(to == SocketType::FLOAT) { - if(from == SocketType::COLOR) - /* color to float */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out)); - else - /* vector/point/normal to float */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out)); - } - else if(to == SocketType::INT) { - if(from == SocketType::COLOR) - /* color to int */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out)); - else - /* vector/point/normal to int */ - compiler.add_node(NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out)); - } - else { - /* float3 to float3 */ - if(in->link) { - /* no op in SVM */ - compiler.stack_link(in, out); - } - else { - /* set 0,0,0 value */ - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out)); - compiler.add_node(NODE_VALUE_V, value_color); - } - } -} - -void ConvertNode::compile(OSLCompiler& compiler) -{ - /* proxy nodes should have been removed at this point */ - assert(special_type != SHADER_SPECIAL_TYPE_PROXY); - - if(from == SocketType::FLOAT) - compiler.add(this, "node_convert_from_float"); - else if(from == SocketType::INT) - compiler.add(this, "node_convert_from_int"); - else if(from == SocketType::COLOR) - compiler.add(this, "node_convert_from_color"); - else if(from == SocketType::VECTOR) - compiler.add(this, "node_convert_from_vector"); - else if(from == SocketType::POINT) - compiler.add(this, "node_convert_from_point"); - else if(from == SocketType::NORMAL) - compiler.add(this, "node_convert_from_normal"); - else - assert(0); + : ShaderNode(node_types[from_][to_]) +{ + from = from_; + to = to_; + + if (from == to) + special_type = SHADER_SPECIAL_TYPE_PROXY; + else if (autoconvert) + special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; +} + +void ConvertNode::constant_fold(const ConstantFolder &folder) +{ + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); + + /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ + + if (folder.all_inputs_constant()) { + if (from == SocketType::FLOAT) { + if (SocketType::is_float3(to)) { + folder.make_constant(make_float3(value_float, value_float, value_float)); + } + } + else if (SocketType::is_float3(from)) { + if (to == SocketType::FLOAT) { + if (from == SocketType::COLOR) { + /* color to float */ + float val = folder.scene->shader_manager->linear_rgb_to_gray(value_color); + folder.make_constant(val); + } + else { + /* vector/point/normal to float */ + folder.make_constant(average(value_vector)); + } + } + else if (SocketType::is_float3(to)) { + folder.make_constant(value_color); + } + } + } + else { + ShaderInput *in = inputs[0]; + ShaderNode *prev = in->link->parent; + + /* no-op conversion of A to B to A */ + if (prev->type == node_types[to][from]) { + ShaderInput *prev_in = prev->inputs[0]; + + if (SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) && + prev_in->link) { + folder.bypass(prev_in->link); + } + } + } +} + +void ConvertNode::compile(SVMCompiler &compiler) +{ + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); + + ShaderInput *in = inputs[0]; + ShaderOutput *out = outputs[0]; + + if (from == SocketType::FLOAT) { + if (to == SocketType::INT) + /* float to int */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out)); + else + /* float to float3 */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out)); + } + else if (from == SocketType::INT) { + if (to == SocketType::FLOAT) + /* int to float */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out)); + else + /* int to vector/point/normal */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out)); + } + else if (to == SocketType::FLOAT) { + if (from == SocketType::COLOR) + /* color to float */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out)); + else + /* vector/point/normal to float */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out)); + } + else if (to == SocketType::INT) { + if (from == SocketType::COLOR) + /* color to int */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out)); + else + /* vector/point/normal to int */ + compiler.add_node( + NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out)); + } + else { + /* float3 to float3 */ + if (in->link) { + /* no op in SVM */ + compiler.stack_link(in, out); + } + else { + /* set 0,0,0 value */ + compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out)); + compiler.add_node(NODE_VALUE_V, value_color); + } + } +} + +void ConvertNode::compile(OSLCompiler &compiler) +{ + /* proxy nodes should have been removed at this point */ + assert(special_type != SHADER_SPECIAL_TYPE_PROXY); + + if (from == SocketType::FLOAT) + compiler.add(this, "node_convert_from_float"); + else if (from == SocketType::INT) + compiler.add(this, "node_convert_from_int"); + else if (from == SocketType::COLOR) + compiler.add(this, "node_convert_from_color"); + else if (from == SocketType::VECTOR) + compiler.add(this, "node_convert_from_vector"); + else if (from == SocketType::POINT) + compiler.add(this, "node_convert_from_point"); + else if (from == SocketType::NORMAL) + compiler.add(this, "node_convert_from_normal"); + else + assert(0); } /* Base type for all closure-type nodes */ -BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) - : ShaderNode(node_type) +BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) : ShaderNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_CLOSURE; + special_type = SHADER_SPECIAL_TYPE_CLOSURE; } bool BsdfBaseNode::has_bump() { - /* detect if anything is plugged into the normal input besides the default */ - ShaderInput *normal_in = input("Normal"); - return (normal_in && normal_in->link && - normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); + /* detect if anything is plugged into the normal input besides the default */ + ShaderInput *normal_in = input("Normal"); + return (normal_in && normal_in->link && + normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); } /* BSDF Closure */ -BsdfNode::BsdfNode(const NodeType *node_type) -: BsdfBaseNode(node_type) +BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type) { } -void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4) +void BsdfNode::compile(SVMCompiler &compiler, + ShaderInput *param1, + ShaderInput *param2, + ShaderInput *param3, + ShaderInput *param4) { - ShaderInput *color_in = input("Color"); - ShaderInput *normal_in = input("Normal"); - ShaderInput *tangent_in = input("Tangent"); + ShaderInput *color_in = input("Color"); + ShaderInput *normal_in = input("Normal"); + ShaderInput *tangent_in = input("Tangent"); - if(color_in->link) - compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); - else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); + if (color_in->link) + compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); - int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID; - int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID; - int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID; - int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID; + int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID; + int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : + SVM_STACK_INVALID; + int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID; + int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID; - compiler.add_node(NODE_CLOSURE_BSDF, - compiler.encode_uchar4(closure, - (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, - (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, - compiler.closure_mix_weight_offset()), - __float_as_int((param1)? get_float(param1->socket_type): 0.0f), - __float_as_int((param2)? get_float(param2->socket_type): 0.0f)); + compiler.add_node( + NODE_CLOSURE_BSDF, + compiler.encode_uchar4(closure, + (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID, + (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID, + compiler.closure_mix_weight_offset()), + __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f), + __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f)); - compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset); + compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset); } -void BsdfNode::compile(SVMCompiler& compiler) +void BsdfNode::compile(SVMCompiler &compiler) { - compile(compiler, NULL, NULL); + compile(compiler, NULL, NULL); } -void BsdfNode::compile(OSLCompiler& /*compiler*/) +void BsdfNode::compile(OSLCompiler & /*compiler*/) { - assert(0); + assert(0); } /* Anisotropic BSDF Closure */ NODE_DEFINE(AnisotropicBsdfNode) { - NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum distribution_enum; - distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); - distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); - distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID); - distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); - SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + static NodeEnum distribution_enum; + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID); + distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); + SOCKET_ENUM( + distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); - SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); + SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); - SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f); - SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f); + SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -AnisotropicBsdfNode::AnisotropicBsdfNode() -: BsdfNode(node_type) +AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; + closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; } void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - ShaderInput *tangent_in = input("Tangent"); + if (shader->has_surface) { + ShaderInput *tangent_in = input("Tangent"); - if(!tangent_in->link) - attributes->add(ATTR_STD_GENERATED); - } + if (!tangent_in->link) + attributes->add(ATTR_STD_GENERATED); + } - ShaderNode::attributes(shader, attributes); + ShaderNode::attributes(shader, attributes); } -void AnisotropicBsdfNode::compile(SVMCompiler& compiler) +void AnisotropicBsdfNode::compile(SVMCompiler &compiler) { - closure = distribution; + closure = distribution; - if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) - BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); - else - BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); + if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) + BsdfNode::compile( + compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); } -void AnisotropicBsdfNode::compile(OSLCompiler& compiler) +void AnisotropicBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "distribution"); - compiler.add(this, "node_anisotropic_bsdf"); + compiler.parameter(this, "distribution"); + compiler.add(this, "node_anisotropic_bsdf"); } /* Glossy BSDF Closure */ NODE_DEFINE(GlossyBsdfNode) { - NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("glossy_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum distribution_enum; - distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID); - distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); - distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); - distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); - distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); - SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); + distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); + SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -GlossyBsdfNode::GlossyBsdfNode() -: BsdfNode(node_type) +GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_MICROFACET_GGX_ID; - distribution_orig = NBUILTIN_CLOSURES; + closure = CLOSURE_BSDF_MICROFACET_GGX_ID; + distribution_orig = NBUILTIN_CLOSURES; } void GlossyBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == NBUILTIN_CLOSURES) { - roughness_orig = roughness; - distribution_orig = distribution; - } - else { - /* By default we use original values, so we don't worry about restoring - * defaults later one and can only do override when needed. - */ - roughness = roughness_orig; - distribution = distribution_orig; - } - Integrator *integrator = scene->integrator; - ShaderInput *roughness_input = input("Roughness"); - if(integrator->filter_glossy == 0.0f) { - /* Fallback to Sharp closure for Roughness close to 0. - * Note: Keep the epsilon in sync with kernel! - */ - if(!roughness_input->link && roughness <= 1e-4f) { - VLOG(1) << "Using sharp glossy BSDF."; - distribution = CLOSURE_BSDF_REFLECTION_ID; - } - } - else { - /* If filter glossy is used we replace Sharp glossy with GGX so we can - * benefit from closure blur to remove unwanted noise. - */ - if(roughness_input->link == NULL && - distribution == CLOSURE_BSDF_REFLECTION_ID) - { - VLOG(1) << "Using GGX glossy with filter glossy."; - distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; - roughness = 0.0f; - } - } - closure = distribution; + if (distribution_orig == NBUILTIN_CLOSURES) { + roughness_orig = roughness; + distribution_orig = distribution; + } + else { + /* By default we use original values, so we don't worry about restoring + * defaults later one and can only do override when needed. + */ + roughness = roughness_orig; + distribution = distribution_orig; + } + Integrator *integrator = scene->integrator; + ShaderInput *roughness_input = input("Roughness"); + if (integrator->filter_glossy == 0.0f) { + /* Fallback to Sharp closure for Roughness close to 0. + * Note: Keep the epsilon in sync with kernel! + */ + if (!roughness_input->link && roughness <= 1e-4f) { + VLOG(1) << "Using sharp glossy BSDF."; + distribution = CLOSURE_BSDF_REFLECTION_ID; + } + } + else { + /* If filter glossy is used we replace Sharp glossy with GGX so we can + * benefit from closure blur to remove unwanted noise. + */ + if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) { + VLOG(1) << "Using GGX glossy with filter glossy."; + distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; + roughness = 0.0f; + } + } + closure = distribution; } bool GlossyBsdfNode::has_integrator_dependency() { - ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && - (distribution == CLOSURE_BSDF_REFLECTION_ID || roughness <= 1e-4f); + ShaderInput *roughness_input = input("Roughness"); + return !roughness_input->link && + (distribution == CLOSURE_BSDF_REFLECTION_ID || roughness <= 1e-4f); } -void GlossyBsdfNode::compile(SVMCompiler& compiler) +void GlossyBsdfNode::compile(SVMCompiler &compiler) { - closure = distribution; + closure = distribution; - if(closure == CLOSURE_BSDF_REFLECTION_ID) - BsdfNode::compile(compiler, NULL, NULL); - else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) - BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color")); - else - BsdfNode::compile(compiler, input("Roughness"), NULL); + if (closure == CLOSURE_BSDF_REFLECTION_ID) + BsdfNode::compile(compiler, NULL, NULL); + else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) + BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), NULL); } -void GlossyBsdfNode::compile(OSLCompiler& compiler) +void GlossyBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "distribution"); - compiler.add(this, "node_glossy_bsdf"); + compiler.parameter(this, "distribution"); + compiler.add(this, "node_glossy_bsdf"); } /* Glass BSDF Closure */ NODE_DEFINE(GlassBsdfNode) { - NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("glass_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum distribution_enum; - distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); - distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); - distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); - distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); - SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); - SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + SOCKET_ENUM( + distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -GlassBsdfNode::GlassBsdfNode() -: BsdfNode(node_type) +GlassBsdfNode::GlassBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_SHARP_GLASS_ID; - distribution_orig = NBUILTIN_CLOSURES; + closure = CLOSURE_BSDF_SHARP_GLASS_ID; + distribution_orig = NBUILTIN_CLOSURES; } void GlassBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == NBUILTIN_CLOSURES) { - roughness_orig = roughness; - distribution_orig = distribution; - } - else { - /* By default we use original values, so we don't worry about restoring - * defaults later one and can only do override when needed. - */ - roughness = roughness_orig; - distribution = distribution_orig; - } - Integrator *integrator = scene->integrator; - ShaderInput *roughness_input = input("Roughness"); - if(integrator->filter_glossy == 0.0f) { - /* Fallback to Sharp closure for Roughness close to 0. - * Note: Keep the epsilon in sync with kernel! - */ - if(!roughness_input->link && roughness <= 1e-4f) { - VLOG(1) << "Using sharp glass BSDF."; - distribution = CLOSURE_BSDF_SHARP_GLASS_ID; - } - } - else { - /* If filter glossy is used we replace Sharp glossy with GGX so we can - * benefit from closure blur to remove unwanted noise. - */ - if(roughness_input->link == NULL && - distribution == CLOSURE_BSDF_SHARP_GLASS_ID) - { - VLOG(1) << "Using GGX glass with filter glossy."; - distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; - roughness = 0.0f; - } - } - closure = distribution; + if (distribution_orig == NBUILTIN_CLOSURES) { + roughness_orig = roughness; + distribution_orig = distribution; + } + else { + /* By default we use original values, so we don't worry about restoring + * defaults later one and can only do override when needed. + */ + roughness = roughness_orig; + distribution = distribution_orig; + } + Integrator *integrator = scene->integrator; + ShaderInput *roughness_input = input("Roughness"); + if (integrator->filter_glossy == 0.0f) { + /* Fallback to Sharp closure for Roughness close to 0. + * Note: Keep the epsilon in sync with kernel! + */ + if (!roughness_input->link && roughness <= 1e-4f) { + VLOG(1) << "Using sharp glass BSDF."; + distribution = CLOSURE_BSDF_SHARP_GLASS_ID; + } + } + else { + /* If filter glossy is used we replace Sharp glossy with GGX so we can + * benefit from closure blur to remove unwanted noise. + */ + if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) { + VLOG(1) << "Using GGX glass with filter glossy."; + distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; + roughness = 0.0f; + } + } + closure = distribution; } bool GlassBsdfNode::has_integrator_dependency() { - ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && - (distribution == CLOSURE_BSDF_SHARP_GLASS_ID || roughness <= 1e-4f); + ShaderInput *roughness_input = input("Roughness"); + return !roughness_input->link && + (distribution == CLOSURE_BSDF_SHARP_GLASS_ID || roughness <= 1e-4f); } -void GlassBsdfNode::compile(SVMCompiler& compiler) +void GlassBsdfNode::compile(SVMCompiler &compiler) { - closure = distribution; + closure = distribution; - if(closure == CLOSURE_BSDF_SHARP_GLASS_ID) - BsdfNode::compile(compiler, NULL, input("IOR")); - else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) - BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color")); - else - BsdfNode::compile(compiler, input("Roughness"), input("IOR")); + if (closure == CLOSURE_BSDF_SHARP_GLASS_ID) + BsdfNode::compile(compiler, NULL, input("IOR")); + else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) + BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), input("IOR")); } -void GlassBsdfNode::compile(OSLCompiler& compiler) +void GlassBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "distribution"); - compiler.add(this, "node_glass_bsdf"); + compiler.parameter(this, "distribution"); + compiler.add(this, "node_glass_bsdf"); } /* Refraction BSDF Closure */ NODE_DEFINE(RefractionBsdfNode) { - NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("refraction_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum distribution_enum; - distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID); - distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); - distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); - SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + static NodeEnum distribution_enum; + distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID); + distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + SOCKET_ENUM( + distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); - SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -RefractionBsdfNode::RefractionBsdfNode() -: BsdfNode(node_type) +RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_REFRACTION_ID; - distribution_orig = NBUILTIN_CLOSURES; + closure = CLOSURE_BSDF_REFRACTION_ID; + distribution_orig = NBUILTIN_CLOSURES; } void RefractionBsdfNode::simplify_settings(Scene *scene) { - if(distribution_orig == NBUILTIN_CLOSURES) { - roughness_orig = roughness; - distribution_orig = distribution; - } - else { - /* By default we use original values, so we don't worry about restoring - * defaults later one and can only do override when needed. - */ - roughness = roughness_orig; - distribution = distribution_orig; - } - Integrator *integrator = scene->integrator; - ShaderInput *roughness_input = input("Roughness"); - if(integrator->filter_glossy == 0.0f) { - /* Fallback to Sharp closure for Roughness close to 0. - * Note: Keep the epsilon in sync with kernel! - */ - if(!roughness_input->link && roughness <= 1e-4f) { - VLOG(1) << "Using sharp refraction BSDF."; - distribution = CLOSURE_BSDF_REFRACTION_ID; - } - } - else { - /* If filter glossy is used we replace Sharp glossy with GGX so we can - * benefit from closure blur to remove unwanted noise. - */ - if(roughness_input->link == NULL && - distribution == CLOSURE_BSDF_REFRACTION_ID) - { - VLOG(1) << "Using GGX refraction with filter glossy."; - distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - roughness = 0.0f; - } - } - closure = distribution; + if (distribution_orig == NBUILTIN_CLOSURES) { + roughness_orig = roughness; + distribution_orig = distribution; + } + else { + /* By default we use original values, so we don't worry about restoring + * defaults later one and can only do override when needed. + */ + roughness = roughness_orig; + distribution = distribution_orig; + } + Integrator *integrator = scene->integrator; + ShaderInput *roughness_input = input("Roughness"); + if (integrator->filter_glossy == 0.0f) { + /* Fallback to Sharp closure for Roughness close to 0. + * Note: Keep the epsilon in sync with kernel! + */ + if (!roughness_input->link && roughness <= 1e-4f) { + VLOG(1) << "Using sharp refraction BSDF."; + distribution = CLOSURE_BSDF_REFRACTION_ID; + } + } + else { + /* If filter glossy is used we replace Sharp glossy with GGX so we can + * benefit from closure blur to remove unwanted noise. + */ + if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) { + VLOG(1) << "Using GGX refraction with filter glossy."; + distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + roughness = 0.0f; + } + } + closure = distribution; } bool RefractionBsdfNode::has_integrator_dependency() { - ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && - (distribution == CLOSURE_BSDF_REFRACTION_ID || roughness <= 1e-4f); + ShaderInput *roughness_input = input("Roughness"); + return !roughness_input->link && + (distribution == CLOSURE_BSDF_REFRACTION_ID || roughness <= 1e-4f); } -void RefractionBsdfNode::compile(SVMCompiler& compiler) +void RefractionBsdfNode::compile(SVMCompiler &compiler) { - closure = distribution; + closure = distribution; - if(closure == CLOSURE_BSDF_REFRACTION_ID) - BsdfNode::compile(compiler, NULL, input("IOR")); - else - BsdfNode::compile(compiler, input("Roughness"), input("IOR")); + if (closure == CLOSURE_BSDF_REFRACTION_ID) + BsdfNode::compile(compiler, NULL, input("IOR")); + else + BsdfNode::compile(compiler, input("Roughness"), input("IOR")); } -void RefractionBsdfNode::compile(OSLCompiler& compiler) +void RefractionBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "distribution"); - compiler.add(this, "node_refraction_bsdf"); + compiler.parameter(this, "distribution"); + compiler.add(this, "node_refraction_bsdf"); } /* Toon BSDF Closure */ NODE_DEFINE(ToonBsdfNode) { - NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("toon_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum component_enum; - component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); - component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); - SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID); - SOCKET_IN_FLOAT(size, "Size", 0.5f); - SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); + static NodeEnum component_enum; + component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID); + component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID); + SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID); + SOCKET_IN_FLOAT(size, "Size", 0.5f); + SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -ToonBsdfNode::ToonBsdfNode() -: BsdfNode(node_type) +ToonBsdfNode::ToonBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_DIFFUSE_TOON_ID; + closure = CLOSURE_BSDF_DIFFUSE_TOON_ID; } -void ToonBsdfNode::compile(SVMCompiler& compiler) +void ToonBsdfNode::compile(SVMCompiler &compiler) { - closure = component; + closure = component; - BsdfNode::compile(compiler, input("Size"), input("Smooth")); + BsdfNode::compile(compiler, input("Size"), input("Smooth")); } -void ToonBsdfNode::compile(OSLCompiler& compiler) +void ToonBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "component"); - compiler.add(this, "node_toon_bsdf"); + compiler.parameter(this, "component"); + compiler.add(this, "node_toon_bsdf"); } /* Velvet BSDF Closure */ NODE_DEFINE(VelvetBsdfNode) { - NodeType* type = NodeType::add("velvet_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("velvet_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -VelvetBsdfNode::VelvetBsdfNode() -: BsdfNode(node_type) +VelvetBsdfNode::VelvetBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; + closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; } -void VelvetBsdfNode::compile(SVMCompiler& compiler) +void VelvetBsdfNode::compile(SVMCompiler &compiler) { - BsdfNode::compile(compiler, input("Sigma"), NULL); + BsdfNode::compile(compiler, input("Sigma"), NULL); } -void VelvetBsdfNode::compile(OSLCompiler& compiler) +void VelvetBsdfNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_velvet_bsdf"); + compiler.add(this, "node_velvet_bsdf"); } /* Diffuse BSDF Closure */ NODE_DEFINE(DiffuseBsdfNode) { - NodeType* type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -DiffuseBsdfNode::DiffuseBsdfNode() -: BsdfNode(node_type) +DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_DIFFUSE_ID; + closure = CLOSURE_BSDF_DIFFUSE_ID; } -void DiffuseBsdfNode::compile(SVMCompiler& compiler) +void DiffuseBsdfNode::compile(SVMCompiler &compiler) { - BsdfNode::compile(compiler, input("Roughness"), NULL); + BsdfNode::compile(compiler, input("Roughness"), NULL); } -void DiffuseBsdfNode::compile(OSLCompiler& compiler) +void DiffuseBsdfNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_diffuse_bsdf"); + compiler.add(this, "node_diffuse_bsdf"); } /* Disney principled BSDF Closure */ NODE_DEFINE(PrincipledBsdfNode) { - NodeType* type = NodeType::add("principled_bsdf", create, NodeType::SHADER); - - static NodeEnum distribution_enum; - distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); - distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); - SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); - - static NodeEnum subsurface_method_enum; - subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_PRINCIPLED_ID); - subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID); - SOCKET_ENUM(subsurface_method, "Subsurface Method", subsurface_method_enum, CLOSURE_BSSRDF_PRINCIPLED_ID); - - SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f); - SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f); - SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f)); - SOCKET_IN_FLOAT(specular, "Specular", 0.0f); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); - SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f); - SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f); - SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); - SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f); - SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f); - SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f); - SOCKET_IN_FLOAT(ior, "IOR", 0.0f); - SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f); - SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f); - SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_NORMAL(clearcoat_normal, "Clearcoat Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_NORMAL(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - - return type; -} - -PrincipledBsdfNode::PrincipledBsdfNode() - : BsdfBaseNode(node_type) -{ - closure = CLOSURE_BSDF_PRINCIPLED_ID; - distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - distribution_orig = NBUILTIN_CLOSURES; + NodeType *type = NodeType::add("principled_bsdf", create, NodeType::SHADER); + + static NodeEnum distribution_enum; + distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + SOCKET_ENUM( + distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + + static NodeEnum subsurface_method_enum; + subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_PRINCIPLED_ID); + subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID); + SOCKET_ENUM(subsurface_method, + "Subsurface Method", + subsurface_method_enum, + CLOSURE_BSSRDF_PRINCIPLED_ID); + + SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f); + SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f); + SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f)); + SOCKET_IN_FLOAT(specular, "Specular", 0.0f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); + SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f); + SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f); + SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); + SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f); + SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f); + SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f); + SOCKET_IN_FLOAT(ior, "IOR", 0.0f); + SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f); + SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f); + SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(clearcoat_normal, + "Clearcoat Normal", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + +PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(node_type) +{ + closure = CLOSURE_BSDF_PRINCIPLED_ID; + distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + distribution_orig = NBUILTIN_CLOSURES; } bool PrincipledBsdfNode::has_surface_bssrdf() { - ShaderInput *subsurface_in = input("Subsurface"); - return (subsurface_in->link != NULL || subsurface > CLOSURE_WEIGHT_CUTOFF); + ShaderInput *subsurface_in = input("Subsurface"); + return (subsurface_in->link != NULL || subsurface > CLOSURE_WEIGHT_CUTOFF); } void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - ShaderInput *tangent_in = input("Tangent"); - - if(!tangent_in->link) - attributes->add(ATTR_STD_GENERATED); - } - - ShaderNode::attributes(shader, attributes); -} - -void PrincipledBsdfNode::compile(SVMCompiler& compiler, ShaderInput *p_metallic, ShaderInput *p_subsurface, ShaderInput *p_subsurface_radius, - ShaderInput *p_specular, ShaderInput *p_roughness, ShaderInput *p_specular_tint, ShaderInput *p_anisotropic, - ShaderInput *p_sheen, ShaderInput *p_sheen_tint, ShaderInput *p_clearcoat, ShaderInput *p_clearcoat_roughness, - ShaderInput *p_ior, ShaderInput *p_transmission, ShaderInput *p_anisotropic_rotation, ShaderInput *p_transmission_roughness) -{ - ShaderInput *base_color_in = input("Base Color"); - ShaderInput *subsurface_color_in = input("Subsurface Color"); - ShaderInput *normal_in = input("Normal"); - ShaderInput *clearcoat_normal_in = input("Clearcoat Normal"); - ShaderInput *tangent_in = input("Tangent"); - - float3 weight = make_float3(1.0f, 1.0f, 1.0f); - - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight); - - int normal_offset = compiler.stack_assign_if_linked(normal_in); - int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in); - int tangent_offset = compiler.stack_assign_if_linked(tangent_in); - int specular_offset = compiler.stack_assign(p_specular); - int roughness_offset = compiler.stack_assign(p_roughness); - int specular_tint_offset = compiler.stack_assign(p_specular_tint); - int anisotropic_offset = compiler.stack_assign(p_anisotropic); - int sheen_offset = compiler.stack_assign(p_sheen); - int sheen_tint_offset = compiler.stack_assign(p_sheen_tint); - int clearcoat_offset = compiler.stack_assign(p_clearcoat); - int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness); - int ior_offset = compiler.stack_assign(p_ior); - int transmission_offset = compiler.stack_assign(p_transmission); - int transmission_roughness_offset = compiler.stack_assign(p_transmission_roughness); - int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation); - int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius); - - compiler.add_node(NODE_CLOSURE_BSDF, - compiler.encode_uchar4(closure, - compiler.stack_assign(p_metallic), - compiler.stack_assign(p_subsurface), - compiler.closure_mix_weight_offset()), - __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f), - __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f)); - - compiler.add_node(normal_offset, tangent_offset, - compiler.encode_uchar4(specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset), - compiler.encode_uchar4(sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset)); - - compiler.add_node(compiler.encode_uchar4(ior_offset, transmission_offset, anisotropic_rotation_offset, transmission_roughness_offset), - distribution, subsurface_method, SVM_STACK_INVALID); - - float3 bc_default = get_float3(base_color_in->socket_type); - - compiler.add_node(((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID), - __float_as_int(bc_default.x), __float_as_int(bc_default.y), __float_as_int(bc_default.z)); - - compiler.add_node(clearcoat_normal_offset, subsurface_radius_offset, SVM_STACK_INVALID, SVM_STACK_INVALID); - - float3 ss_default = get_float3(subsurface_color_in->socket_type); - - compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) : SVM_STACK_INVALID), - __float_as_int(ss_default.x), __float_as_int(ss_default.y), __float_as_int(ss_default.z)); + if (shader->has_surface) { + ShaderInput *tangent_in = input("Tangent"); + + if (!tangent_in->link) + attributes->add(ATTR_STD_GENERATED); + } + + ShaderNode::attributes(shader, attributes); +} + +void PrincipledBsdfNode::compile(SVMCompiler &compiler, + ShaderInput *p_metallic, + ShaderInput *p_subsurface, + ShaderInput *p_subsurface_radius, + ShaderInput *p_specular, + ShaderInput *p_roughness, + ShaderInput *p_specular_tint, + ShaderInput *p_anisotropic, + ShaderInput *p_sheen, + ShaderInput *p_sheen_tint, + ShaderInput *p_clearcoat, + ShaderInput *p_clearcoat_roughness, + ShaderInput *p_ior, + ShaderInput *p_transmission, + ShaderInput *p_anisotropic_rotation, + ShaderInput *p_transmission_roughness) +{ + ShaderInput *base_color_in = input("Base Color"); + ShaderInput *subsurface_color_in = input("Subsurface Color"); + ShaderInput *normal_in = input("Normal"); + ShaderInput *clearcoat_normal_in = input("Clearcoat Normal"); + ShaderInput *tangent_in = input("Tangent"); + + float3 weight = make_float3(1.0f, 1.0f, 1.0f); + + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight); + + int normal_offset = compiler.stack_assign_if_linked(normal_in); + int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in); + int tangent_offset = compiler.stack_assign_if_linked(tangent_in); + int specular_offset = compiler.stack_assign(p_specular); + int roughness_offset = compiler.stack_assign(p_roughness); + int specular_tint_offset = compiler.stack_assign(p_specular_tint); + int anisotropic_offset = compiler.stack_assign(p_anisotropic); + int sheen_offset = compiler.stack_assign(p_sheen); + int sheen_tint_offset = compiler.stack_assign(p_sheen_tint); + int clearcoat_offset = compiler.stack_assign(p_clearcoat); + int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness); + int ior_offset = compiler.stack_assign(p_ior); + int transmission_offset = compiler.stack_assign(p_transmission); + int transmission_roughness_offset = compiler.stack_assign(p_transmission_roughness); + int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation); + int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius); + + compiler.add_node(NODE_CLOSURE_BSDF, + compiler.encode_uchar4(closure, + compiler.stack_assign(p_metallic), + compiler.stack_assign(p_subsurface), + compiler.closure_mix_weight_offset()), + __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f), + __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f)); + + compiler.add_node( + normal_offset, + tangent_offset, + compiler.encode_uchar4( + specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset), + compiler.encode_uchar4( + sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset)); + + compiler.add_node(compiler.encode_uchar4(ior_offset, + transmission_offset, + anisotropic_rotation_offset, + transmission_roughness_offset), + distribution, + subsurface_method, + SVM_STACK_INVALID); + + float3 bc_default = get_float3(base_color_in->socket_type); + + compiler.add_node( + ((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID), + __float_as_int(bc_default.x), + __float_as_int(bc_default.y), + __float_as_int(bc_default.z)); + + compiler.add_node( + clearcoat_normal_offset, subsurface_radius_offset, SVM_STACK_INVALID, SVM_STACK_INVALID); + + float3 ss_default = get_float3(subsurface_color_in->socket_type); + + compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) : + SVM_STACK_INVALID), + __float_as_int(ss_default.x), + __float_as_int(ss_default.y), + __float_as_int(ss_default.z)); } bool PrincipledBsdfNode::has_integrator_dependency() { - ShaderInput *roughness_input = input("Roughness"); - return !roughness_input->link && roughness <= 1e-4f; + ShaderInput *roughness_input = input("Roughness"); + return !roughness_input->link && roughness <= 1e-4f; } -void PrincipledBsdfNode::compile(SVMCompiler& compiler) +void PrincipledBsdfNode::compile(SVMCompiler &compiler) { - compile(compiler, input("Metallic"), input("Subsurface"), input("Subsurface Radius"), input("Specular"), - input("Roughness"), input("Specular Tint"), input("Anisotropic"), input("Sheen"), input("Sheen Tint"), - input("Clearcoat"), input("Clearcoat Roughness"), input("IOR"), input("Transmission"), - input("Anisotropic Rotation"), input("Transmission Roughness")); + compile(compiler, + input("Metallic"), + input("Subsurface"), + input("Subsurface Radius"), + input("Specular"), + input("Roughness"), + input("Specular Tint"), + input("Anisotropic"), + input("Sheen"), + input("Sheen Tint"), + input("Clearcoat"), + input("Clearcoat Roughness"), + input("IOR"), + input("Transmission"), + input("Anisotropic Rotation"), + input("Transmission Roughness")); } -void PrincipledBsdfNode::compile(OSLCompiler& compiler) +void PrincipledBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "distribution"); - compiler.parameter(this, "subsurface_method"); - compiler.add(this, "node_principled_bsdf"); + compiler.parameter(this, "distribution"); + compiler.parameter(this, "subsurface_method"); + compiler.add(this, "node_principled_bsdf"); } bool PrincipledBsdfNode::has_bssrdf_bump() { - return has_surface_bssrdf() && has_bump(); + return has_surface_bssrdf() && has_bump(); } /* Translucent BSDF Closure */ NODE_DEFINE(TranslucentBsdfNode) { - NodeType* type = NodeType::add("translucent_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("translucent_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -TranslucentBsdfNode::TranslucentBsdfNode() -: BsdfNode(node_type) +TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_TRANSLUCENT_ID; + closure = CLOSURE_BSDF_TRANSLUCENT_ID; } -void TranslucentBsdfNode::compile(SVMCompiler& compiler) +void TranslucentBsdfNode::compile(SVMCompiler &compiler) { - BsdfNode::compile(compiler, NULL, NULL); + BsdfNode::compile(compiler, NULL, NULL); } -void TranslucentBsdfNode::compile(OSLCompiler& compiler) +void TranslucentBsdfNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_translucent_bsdf"); + compiler.add(this, "node_translucent_bsdf"); } /* Transparent BSDF Closure */ NODE_DEFINE(TransparentBsdfNode) { - NodeType* type = NodeType::add("transparent_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("transparent_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -TransparentBsdfNode::TransparentBsdfNode() -: BsdfNode(node_type) +TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_TRANSPARENT_ID; + closure = CLOSURE_BSDF_TRANSPARENT_ID; } -void TransparentBsdfNode::compile(SVMCompiler& compiler) +void TransparentBsdfNode::compile(SVMCompiler &compiler) { - BsdfNode::compile(compiler, NULL, NULL); + BsdfNode::compile(compiler, NULL, NULL); } -void TransparentBsdfNode::compile(OSLCompiler& compiler) +void TransparentBsdfNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_transparent_bsdf"); + compiler.add(this, "node_transparent_bsdf"); } /* Subsurface Scattering Closure */ NODE_DEFINE(SubsurfaceScatteringNode) { - NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER); + NodeType *type = NodeType::add("subsurface_scattering", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum falloff_enum; - falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID); - falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); - falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID); - falloff_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID); - SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID); - SOCKET_IN_FLOAT(scale, "Scale", 0.01f); - SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f)); - SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f); - SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f); + static NodeEnum falloff_enum; + falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID); + falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID); + falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID); + falloff_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID); + SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID); + SOCKET_IN_FLOAT(scale, "Scale", 0.01f); + SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f)); + SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f); + SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f); - SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF"); + SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF"); - return type; + return type; } -SubsurfaceScatteringNode::SubsurfaceScatteringNode() -: BsdfNode(node_type) +SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(node_type) { - closure = falloff; + closure = falloff; } -void SubsurfaceScatteringNode::compile(SVMCompiler& compiler) +void SubsurfaceScatteringNode::compile(SVMCompiler &compiler) { - closure = falloff; - BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness")); + closure = falloff; + BsdfNode::compile( + compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness")); } -void SubsurfaceScatteringNode::compile(OSLCompiler& compiler) +void SubsurfaceScatteringNode::compile(OSLCompiler &compiler) { - closure = falloff; - compiler.parameter(this, "falloff"); - compiler.add(this, "node_subsurface_scattering"); + closure = falloff; + compiler.parameter(this, "falloff"); + compiler.add(this, "node_subsurface_scattering"); } bool SubsurfaceScatteringNode::has_bssrdf_bump() { - /* detect if anything is plugged into the normal input besides the default */ - ShaderInput *normal_in = input("Normal"); - return (normal_in->link && normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); + /* detect if anything is plugged into the normal input besides the default */ + ShaderInput *normal_in = input("Normal"); + return (normal_in->link && + normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY); } /* Emissive Closure */ NODE_DEFINE(EmissionNode) { - NodeType* type = NodeType::add("emission", create, NodeType::SHADER); + NodeType *type = NodeType::add("emission", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(strength, "Strength", 10.0f); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(strength, "Strength", 10.0f); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(emission, "Emission"); + SOCKET_OUT_CLOSURE(emission, "Emission"); - return type; + return type; } -EmissionNode::EmissionNode() -: ShaderNode(node_type) +EmissionNode::EmissionNode() : ShaderNode(node_type) { } -void EmissionNode::compile(SVMCompiler& compiler) +void EmissionNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Color"); - ShaderInput *strength_in = input("Strength"); + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); - if(color_in->link || strength_in->link) { - compiler.add_node(NODE_EMISSION_WEIGHT, - compiler.stack_assign(color_in), - compiler.stack_assign(strength_in)); - } - else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength); + if (color_in->link || strength_in->link) { + compiler.add_node( + NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in)); + } + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength); - compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); + compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); } -void EmissionNode::compile(OSLCompiler& compiler) +void EmissionNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_emission"); + compiler.add(this, "node_emission"); } -void EmissionNode::constant_fold(const ConstantFolder& folder) +void EmissionNode::constant_fold(const ConstantFolder &folder) { - ShaderInput *color_in = input("Color"); - ShaderInput *strength_in = input("Strength"); + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); - if((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)) - { - folder.discard(); - } + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Background Closure */ NODE_DEFINE(BackgroundNode) { - NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER); + NodeType *type = NodeType::add("background_shader", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(strength, "Strength", 1.0f); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(background, "Background"); + SOCKET_OUT_CLOSURE(background, "Background"); - return type; + return type; } -BackgroundNode::BackgroundNode() -: ShaderNode(node_type) +BackgroundNode::BackgroundNode() : ShaderNode(node_type) { } -void BackgroundNode::compile(SVMCompiler& compiler) +void BackgroundNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Color"); - ShaderInput *strength_in = input("Strength"); + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); - if(color_in->link || strength_in->link) { - compiler.add_node(NODE_EMISSION_WEIGHT, - compiler.stack_assign(color_in), - compiler.stack_assign(strength_in)); - } - else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength); + if (color_in->link || strength_in->link) { + compiler.add_node( + NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in)); + } + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength); - compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); + compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); } -void BackgroundNode::compile(OSLCompiler& compiler) +void BackgroundNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_background"); + compiler.add(this, "node_background"); } -void BackgroundNode::constant_fold(const ConstantFolder& folder) +void BackgroundNode::constant_fold(const ConstantFolder &folder) { - ShaderInput *color_in = input("Color"); - ShaderInput *strength_in = input("Strength"); + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); - if((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)) - { - folder.discard(); - } + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Holdout Closure */ NODE_DEFINE(HoldoutNode) { - NodeType* type = NodeType::add("holdout", create, NodeType::SHADER); + NodeType *type = NodeType::add("holdout", create, NodeType::SHADER); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(holdout, "Holdout"); + SOCKET_OUT_CLOSURE(holdout, "Holdout"); - return type; + return type; } -HoldoutNode::HoldoutNode() -: ShaderNode(node_type) +HoldoutNode::HoldoutNode() : ShaderNode(node_type) { } -void HoldoutNode::compile(SVMCompiler& compiler) +void HoldoutNode::compile(SVMCompiler &compiler) { - float3 value = make_float3(1.0f, 1.0f, 1.0f); + float3 value = make_float3(1.0f, 1.0f, 1.0f); - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value); - compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset()); + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value); + compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset()); } -void HoldoutNode::compile(OSLCompiler& compiler) +void HoldoutNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_holdout"); + compiler.add(this, "node_holdout"); } /* Ambient Occlusion */ NODE_DEFINE(AmbientOcclusionNode) { - NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER); + NodeType *type = NodeType::add("ambient_occlusion", create, NodeType::SHADER); - SOCKET_INT(samples, "Samples", 16); + SOCKET_INT(samples, "Samples", 16); - SOCKET_IN_COLOR(color, "Color", make_float3(1.0f, 1.0f, 1.0f)); - SOCKET_IN_FLOAT(distance, "Distance", 1.0f); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_COLOR(color, "Color", make_float3(1.0f, 1.0f, 1.0f)); + SOCKET_IN_FLOAT(distance, "Distance", 1.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_BOOLEAN(inside, "Inside", false); - SOCKET_BOOLEAN(only_local, "Only Local", false); + SOCKET_BOOLEAN(inside, "Inside", false); + SOCKET_BOOLEAN(only_local, "Only Local", false); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(ao, "AO"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(ao, "AO"); - return type; + return type; } -AmbientOcclusionNode::AmbientOcclusionNode() -: ShaderNode(node_type) +AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(node_type) { } -void AmbientOcclusionNode::compile(SVMCompiler& compiler) +void AmbientOcclusionNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Color"); - ShaderInput *distance_in = input("Distance"); - ShaderInput *normal_in = input("Normal"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *ao_out = output("AO"); + ShaderInput *color_in = input("Color"); + ShaderInput *distance_in = input("Distance"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *ao_out = output("AO"); - int flags = (inside? NODE_AO_INSIDE : 0) | (only_local? NODE_AO_ONLY_LOCAL : 0); + int flags = (inside ? NODE_AO_INSIDE : 0) | (only_local ? NODE_AO_ONLY_LOCAL : 0); - if(!distance_in->link && distance == 0.0f) { - flags |= NODE_AO_GLOBAL_RADIUS; - } + if (!distance_in->link && distance == 0.0f) { + flags |= NODE_AO_GLOBAL_RADIUS; + } - compiler.add_node(NODE_AMBIENT_OCCLUSION, - compiler.encode_uchar4(flags, - compiler.stack_assign_if_linked(distance_in), - compiler.stack_assign_if_linked(normal_in), - compiler.stack_assign(ao_out)), - compiler.encode_uchar4(compiler.stack_assign(color_in), - compiler.stack_assign(color_out), - samples), - __float_as_uint(distance)); + compiler.add_node(NODE_AMBIENT_OCCLUSION, + compiler.encode_uchar4(flags, + compiler.stack_assign_if_linked(distance_in), + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(ao_out)), + compiler.encode_uchar4(compiler.stack_assign(color_in), + compiler.stack_assign(color_out), + samples), + __float_as_uint(distance)); } -void AmbientOcclusionNode::compile(OSLCompiler& compiler) +void AmbientOcclusionNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "samples"); - compiler.parameter(this, "inside"); - compiler.parameter(this, "only_local"); - compiler.add(this, "node_ambient_occlusion"); + compiler.parameter(this, "samples"); + compiler.parameter(this, "inside"); + compiler.parameter(this, "only_local"); + compiler.add(this, "node_ambient_occlusion"); } /* Volume Closure */ -VolumeNode::VolumeNode(const NodeType *node_type) -: ShaderNode(node_type) +VolumeNode::VolumeNode(const NodeType *node_type) : ShaderNode(node_type) { - closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; + closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; } -void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) +void VolumeNode::compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2) { - ShaderInput *color_in = input("Color"); + ShaderInput *color_in = input("Color"); - if(color_in->link) - compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); - else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); + if (color_in->link) + compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); - compiler.add_node(NODE_CLOSURE_VOLUME, - compiler.encode_uchar4(closure, - (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID, - (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID, - compiler.closure_mix_weight_offset()), - __float_as_int((param1)? get_float(param1->socket_type): 0.0f), - __float_as_int((param2)? get_float(param2->socket_type): 0.0f)); + compiler.add_node( + NODE_CLOSURE_VOLUME, + compiler.encode_uchar4(closure, + (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID, + (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID, + compiler.closure_mix_weight_offset()), + __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f), + __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f)); } -void VolumeNode::compile(SVMCompiler& compiler) +void VolumeNode::compile(SVMCompiler &compiler) { - compile(compiler, NULL, NULL); + compile(compiler, NULL, NULL); } -void VolumeNode::compile(OSLCompiler& /*compiler*/) +void VolumeNode::compile(OSLCompiler & /*compiler*/) { - assert(0); + assert(0); } /* Absorption Volume Closure */ NODE_DEFINE(AbsorptionVolumeNode) { - NodeType* type = NodeType::add("absorption_volume", create, NodeType::SHADER); + NodeType *type = NodeType::add("absorption_volume", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(density, "Density", 1.0f); - SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(volume, "Volume"); + SOCKET_OUT_CLOSURE(volume, "Volume"); - return type; + return type; } -AbsorptionVolumeNode::AbsorptionVolumeNode() -: VolumeNode(node_type) +AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(node_type) { - closure = CLOSURE_VOLUME_ABSORPTION_ID; + closure = CLOSURE_VOLUME_ABSORPTION_ID; } -void AbsorptionVolumeNode::compile(SVMCompiler& compiler) +void AbsorptionVolumeNode::compile(SVMCompiler &compiler) { - VolumeNode::compile(compiler, input("Density"), NULL); + VolumeNode::compile(compiler, input("Density"), NULL); } -void AbsorptionVolumeNode::compile(OSLCompiler& compiler) +void AbsorptionVolumeNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_absorption_volume"); + compiler.add(this, "node_absorption_volume"); } /* Scatter Volume Closure */ NODE_DEFINE(ScatterVolumeNode) { - NodeType* type = NodeType::add("scatter_volume", create, NodeType::SHADER); + NodeType *type = NodeType::add("scatter_volume", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(density, "Density", 1.0f); - SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f); - SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(volume, "Volume"); + SOCKET_OUT_CLOSURE(volume, "Volume"); - return type; + return type; } -ScatterVolumeNode::ScatterVolumeNode() -: VolumeNode(node_type) +ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(node_type) { - closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; + closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; } -void ScatterVolumeNode::compile(SVMCompiler& compiler) +void ScatterVolumeNode::compile(SVMCompiler &compiler) { - VolumeNode::compile(compiler, input("Density"), input("Anisotropy")); + VolumeNode::compile(compiler, input("Density"), input("Anisotropy")); } -void ScatterVolumeNode::compile(OSLCompiler& compiler) +void ScatterVolumeNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_scatter_volume"); + compiler.add(this, "node_scatter_volume"); } /* Principled Volume Closure */ NODE_DEFINE(PrincipledVolumeNode) { - NodeType* type = NodeType::add("principled_volume", create, NodeType::SHADER); + NodeType *type = NodeType::add("principled_volume", create, NodeType::SHADER); - SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring()); - SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring()); - SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring()); + SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring()); + SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring()); + SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring()); - SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f)); - SOCKET_IN_FLOAT(density, "Density", 1.0f); - SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f); - SOCKET_IN_COLOR(absorption_color, "Absorption Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f); - SOCKET_IN_COLOR(emission_color, "Emission Color", make_float3(1.0f, 1.0f, 1.0f)); - SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f); - SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", make_float3(1.0f, 1.0f, 1.0f)); - SOCKET_IN_FLOAT(temperature, "Temperature", 1500.0f); - SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f)); + SOCKET_IN_FLOAT(density, "Density", 1.0f); + SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f); + SOCKET_IN_COLOR(absorption_color, "Absorption Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f); + SOCKET_IN_COLOR(emission_color, "Emission Color", make_float3(1.0f, 1.0f, 1.0f)); + SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f); + SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", make_float3(1.0f, 1.0f, 1.0f)); + SOCKET_IN_FLOAT(temperature, "Temperature", 1500.0f); + SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(volume, "Volume"); + SOCKET_OUT_CLOSURE(volume, "Volume"); - return type; + return type; } -PrincipledVolumeNode::PrincipledVolumeNode() -: VolumeNode(node_type) +PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(node_type) { - closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; + closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID; } void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_volume) { - ShaderInput *density_in = input("Density"); - ShaderInput *blackbody_in = input("Blackbody Intensity"); - - if(density_in->link || density > 0.0f) { - attributes->add_standard(density_attribute); - attributes->add_standard(color_attribute); - } - - if(blackbody_in->link || blackbody_intensity > 0.0f) { - attributes->add_standard(temperature_attribute); - } - - attributes->add(ATTR_STD_GENERATED_TRANSFORM); - } - - ShaderNode::attributes(shader, attributes); -} - -void PrincipledVolumeNode::compile(SVMCompiler& compiler) -{ - ShaderInput *color_in = input("Color"); - ShaderInput *density_in = input("Density"); - ShaderInput *anisotropy_in = input("Anisotropy"); - ShaderInput *absorption_color_in = input("Absorption Color"); - ShaderInput *emission_in = input("Emission Strength"); - ShaderInput *emission_color_in = input("Emission Color"); - ShaderInput *blackbody_in = input("Blackbody Intensity"); - ShaderInput *blackbody_tint_in = input("Blackbody Tint"); - ShaderInput *temperature_in = input("Temperature"); - - if(color_in->link) - compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); - else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); - - compiler.add_node(NODE_PRINCIPLED_VOLUME, - compiler.encode_uchar4( - compiler.stack_assign_if_linked(density_in), - compiler.stack_assign_if_linked(anisotropy_in), - compiler.stack_assign(absorption_color_in), - compiler.closure_mix_weight_offset()), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(emission_in), - compiler.stack_assign(emission_color_in), - compiler.stack_assign_if_linked(blackbody_in), - compiler.stack_assign(temperature_in)), - compiler.stack_assign(blackbody_tint_in)); - - int attr_density = compiler.attribute_standard(density_attribute); - int attr_color = compiler.attribute_standard(color_attribute); - int attr_temperature = compiler.attribute_standard(temperature_attribute); - - compiler.add_node( - __float_as_int(density), - __float_as_int(anisotropy), - __float_as_int(emission_strength), - __float_as_int(blackbody_intensity)); - - compiler.add_node( - attr_density, - attr_color, - attr_temperature); -} - -void PrincipledVolumeNode::compile(OSLCompiler& compiler) -{ - if(Attribute::name_standard(density_attribute.c_str())) { - density_attribute = ustring("geom:" + density_attribute.string()); - } - if(Attribute::name_standard(color_attribute.c_str())) { - color_attribute = ustring("geom:" + color_attribute.string()); - } - if(Attribute::name_standard(temperature_attribute.c_str())) { - temperature_attribute = ustring("geom:" + temperature_attribute.string()); - } - - compiler.add(this, "node_principled_volume"); + if (shader->has_volume) { + ShaderInput *density_in = input("Density"); + ShaderInput *blackbody_in = input("Blackbody Intensity"); + + if (density_in->link || density > 0.0f) { + attributes->add_standard(density_attribute); + attributes->add_standard(color_attribute); + } + + if (blackbody_in->link || blackbody_intensity > 0.0f) { + attributes->add_standard(temperature_attribute); + } + + attributes->add(ATTR_STD_GENERATED_TRANSFORM); + } + + ShaderNode::attributes(shader, attributes); +} + +void PrincipledVolumeNode::compile(SVMCompiler &compiler) +{ + ShaderInput *color_in = input("Color"); + ShaderInput *density_in = input("Density"); + ShaderInput *anisotropy_in = input("Anisotropy"); + ShaderInput *absorption_color_in = input("Absorption Color"); + ShaderInput *emission_in = input("Emission Strength"); + ShaderInput *emission_color_in = input("Emission Color"); + ShaderInput *blackbody_in = input("Blackbody Intensity"); + ShaderInput *blackbody_tint_in = input("Blackbody Tint"); + ShaderInput *temperature_in = input("Temperature"); + + if (color_in->link) + compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); + + compiler.add_node(NODE_PRINCIPLED_VOLUME, + compiler.encode_uchar4(compiler.stack_assign_if_linked(density_in), + compiler.stack_assign_if_linked(anisotropy_in), + compiler.stack_assign(absorption_color_in), + compiler.closure_mix_weight_offset()), + compiler.encode_uchar4(compiler.stack_assign_if_linked(emission_in), + compiler.stack_assign(emission_color_in), + compiler.stack_assign_if_linked(blackbody_in), + compiler.stack_assign(temperature_in)), + compiler.stack_assign(blackbody_tint_in)); + + int attr_density = compiler.attribute_standard(density_attribute); + int attr_color = compiler.attribute_standard(color_attribute); + int attr_temperature = compiler.attribute_standard(temperature_attribute); + + compiler.add_node(__float_as_int(density), + __float_as_int(anisotropy), + __float_as_int(emission_strength), + __float_as_int(blackbody_intensity)); + + compiler.add_node(attr_density, attr_color, attr_temperature); +} + +void PrincipledVolumeNode::compile(OSLCompiler &compiler) +{ + if (Attribute::name_standard(density_attribute.c_str())) { + density_attribute = ustring("geom:" + density_attribute.string()); + } + if (Attribute::name_standard(color_attribute.c_str())) { + color_attribute = ustring("geom:" + color_attribute.string()); + } + if (Attribute::name_standard(temperature_attribute.c_str())) { + temperature_attribute = ustring("geom:" + temperature_attribute.string()); + } + + compiler.add(this, "node_principled_volume"); } /* Principled Hair BSDF Closure */ NODE_DEFINE(PrincipledHairBsdfNode) { - NodeType* type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER); - /* Color parametrization specified as enum. */ - static NodeEnum parametrization_enum; - parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE); - parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); - parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION); - SOCKET_ENUM(parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE); + /* Color parametrization specified as enum. */ + static NodeEnum parametrization_enum; + parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE); + parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); + parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION); + SOCKET_ENUM( + parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE); - /* Initialize sockets to their default values. */ - SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f)); - SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f); - SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f); - SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f)); - SOCKET_IN_VECTOR(absorption_coefficient, "Absorption Coefficient", make_float3(0.245531f, 0.52f, 1.365f), SocketType::VECTOR); + /* Initialize sockets to their default values. */ + SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f)); + SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f); + SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f); + SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f)); + SOCKET_IN_VECTOR(absorption_coefficient, + "Absorption Coefficient", + make_float3(0.245531f, 0.52f, 1.365f), + SocketType::VECTOR); - SOCKET_IN_FLOAT(offset, "Offset", 2.f*M_PI_F/180.f); - SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f); - SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f); - SOCKET_IN_FLOAT(coat, "Coat", 0.0f); - SOCKET_IN_FLOAT(ior, "IOR", 1.55f); + SOCKET_IN_FLOAT(offset, "Offset", 2.f * M_PI_F / 180.f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f); + SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f); + SOCKET_IN_FLOAT(coat, "Coat", 0.0f); + SOCKET_IN_FLOAT(ior, "IOR", 1.55f); - SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f); - SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f); - SOCKET_IN_FLOAT(random, "Random", 0.0f); + SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f); + SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f); + SOCKET_IN_FLOAT(random, "Random", 0.0f); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -PrincipledHairBsdfNode::PrincipledHairBsdfNode() -: BsdfBaseNode(node_type) +PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(node_type) { - closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; + closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; } /* Enable retrieving Hair Info -> Random if Random isn't linked. */ void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(!input("Random")->link) { - attributes->add(ATTR_STD_CURVE_RANDOM); - } - ShaderNode::attributes(shader, attributes); + if (!input("Random")->link) { + attributes->add(ATTR_STD_CURVE_RANDOM); + } + ShaderNode::attributes(shader, attributes); } /* Prepares the input data for the SVM shader. */ -void PrincipledHairBsdfNode::compile(SVMCompiler& compiler) -{ - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, make_float3(1.0f, 1.0f, 1.0f)); - - ShaderInput *roughness_in = input("Roughness"); - ShaderInput *radial_roughness_in = input("Radial Roughness"); - ShaderInput *random_roughness_in = input("Random Roughness"); - ShaderInput *offset_in = input("Offset"); - ShaderInput *coat_in = input("Coat"); - ShaderInput *ior_in = input("IOR"); - ShaderInput *melanin_in = input("Melanin"); - ShaderInput *melanin_redness_in = input("Melanin Redness"); - ShaderInput *random_color_in = input("Random Color"); - - int color_ofs = compiler.stack_assign(input("Color")); - int tint_ofs = compiler.stack_assign(input("Tint")); - int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient")); - - ShaderInput *random_in = input("Random"); - int attr_random = random_in->link ? SVM_STACK_INVALID : compiler.attribute(ATTR_STD_CURVE_RANDOM); - - /* Encode all parameters into data nodes. */ - compiler.add_node(NODE_CLOSURE_BSDF, - /* Socket IDs can be packed 4 at a time into a single data packet */ - compiler.encode_uchar4(closure, - compiler.stack_assign_if_linked(roughness_in), - compiler.stack_assign_if_linked(radial_roughness_in), - compiler.closure_mix_weight_offset()), - /* The rest are stored as unsigned integers */ - __float_as_uint(roughness), - __float_as_uint(radial_roughness)); - - compiler.add_node(compiler.stack_assign_if_linked(input("Normal")), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(offset_in), - compiler.stack_assign_if_linked(ior_in), - color_ofs, - parametrization), - __float_as_uint(offset), - __float_as_uint(ior)); - - compiler.add_node( - compiler.encode_uchar4( - compiler.stack_assign_if_linked(coat_in), - compiler.stack_assign_if_linked(melanin_in), - compiler.stack_assign_if_linked(melanin_redness_in), - absorption_coefficient_ofs), - __float_as_uint(coat), - __float_as_uint(melanin), - __float_as_uint(melanin_redness)); - - compiler.add_node( - compiler.encode_uchar4( - tint_ofs, - compiler.stack_assign_if_linked(random_in), - compiler.stack_assign_if_linked(random_color_in), - compiler.stack_assign_if_linked(random_roughness_in)), - __float_as_uint(random), - __float_as_uint(random_color), - __float_as_uint(random_roughness)); - - compiler.add_node( - compiler.encode_uchar4( - SVM_STACK_INVALID, - SVM_STACK_INVALID, - SVM_STACK_INVALID, - SVM_STACK_INVALID), - attr_random, - SVM_STACK_INVALID, - SVM_STACK_INVALID); +void PrincipledHairBsdfNode::compile(SVMCompiler &compiler) +{ + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, make_float3(1.0f, 1.0f, 1.0f)); + + ShaderInput *roughness_in = input("Roughness"); + ShaderInput *radial_roughness_in = input("Radial Roughness"); + ShaderInput *random_roughness_in = input("Random Roughness"); + ShaderInput *offset_in = input("Offset"); + ShaderInput *coat_in = input("Coat"); + ShaderInput *ior_in = input("IOR"); + ShaderInput *melanin_in = input("Melanin"); + ShaderInput *melanin_redness_in = input("Melanin Redness"); + ShaderInput *random_color_in = input("Random Color"); + + int color_ofs = compiler.stack_assign(input("Color")); + int tint_ofs = compiler.stack_assign(input("Tint")); + int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient")); + + ShaderInput *random_in = input("Random"); + int attr_random = random_in->link ? SVM_STACK_INVALID : + compiler.attribute(ATTR_STD_CURVE_RANDOM); + + /* Encode all parameters into data nodes. */ + compiler.add_node(NODE_CLOSURE_BSDF, + /* Socket IDs can be packed 4 at a time into a single data packet */ + compiler.encode_uchar4(closure, + compiler.stack_assign_if_linked(roughness_in), + compiler.stack_assign_if_linked(radial_roughness_in), + compiler.closure_mix_weight_offset()), + /* The rest are stored as unsigned integers */ + __float_as_uint(roughness), + __float_as_uint(radial_roughness)); + + compiler.add_node(compiler.stack_assign_if_linked(input("Normal")), + compiler.encode_uchar4(compiler.stack_assign_if_linked(offset_in), + compiler.stack_assign_if_linked(ior_in), + color_ofs, + parametrization), + __float_as_uint(offset), + __float_as_uint(ior)); + + compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(coat_in), + compiler.stack_assign_if_linked(melanin_in), + compiler.stack_assign_if_linked(melanin_redness_in), + absorption_coefficient_ofs), + __float_as_uint(coat), + __float_as_uint(melanin), + __float_as_uint(melanin_redness)); + + compiler.add_node(compiler.encode_uchar4(tint_ofs, + compiler.stack_assign_if_linked(random_in), + compiler.stack_assign_if_linked(random_color_in), + compiler.stack_assign_if_linked(random_roughness_in)), + __float_as_uint(random), + __float_as_uint(random_color), + __float_as_uint(random_roughness)); + + compiler.add_node( + compiler.encode_uchar4( + SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID), + attr_random, + SVM_STACK_INVALID, + SVM_STACK_INVALID); } /* Prepares the input data for the OSL shader. */ -void PrincipledHairBsdfNode::compile(OSLCompiler& compiler) +void PrincipledHairBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "parametrization"); - compiler.add(this, "node_principled_hair_bsdf"); + compiler.parameter(this, "parametrization"); + compiler.add(this, "node_principled_hair_bsdf"); } /* Hair BSDF Closure */ NODE_DEFINE(HairBsdfNode) { - NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER); + NodeType *type = NodeType::add("hair_bsdf", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); - static NodeEnum component_enum; - component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); - component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); - SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID); - SOCKET_IN_FLOAT(offset, "Offset", 0.0f); - SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f); - SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f); - SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f)); + static NodeEnum component_enum; + component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID); + component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID); + SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID); + SOCKET_IN_FLOAT(offset, "Offset", 0.0f); + SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f); + SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f); + SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); - return type; + return type; } -HairBsdfNode::HairBsdfNode() -: BsdfNode(node_type) +HairBsdfNode::HairBsdfNode() : BsdfNode(node_type) { - closure = CLOSURE_BSDF_HAIR_REFLECTION_ID; + closure = CLOSURE_BSDF_HAIR_REFLECTION_ID; } -void HairBsdfNode::compile(SVMCompiler& compiler) +void HairBsdfNode::compile(SVMCompiler &compiler) { - closure = component; + closure = component; - BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset")); + BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset")); } -void HairBsdfNode::compile(OSLCompiler& compiler) +void HairBsdfNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "component"); - compiler.add(this, "node_hair_bsdf"); + compiler.parameter(this, "component"); + compiler.add(this, "node_hair_bsdf"); } /* Geometry */ NODE_DEFINE(GeometryNode) { - NodeType* type = NodeType::add("geometry", create, NodeType::SHADER); + NodeType *type = NodeType::add("geometry", create, NodeType::SHADER); - SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_NORMAL(normal_osl, + "NormalIn", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - SOCKET_OUT_POINT(position, "Position"); - SOCKET_OUT_NORMAL(normal, "Normal"); - SOCKET_OUT_NORMAL(tangent, "Tangent"); - SOCKET_OUT_NORMAL(true_normal, "True Normal"); - SOCKET_OUT_VECTOR(incoming, "Incoming"); - SOCKET_OUT_POINT(parametric, "Parametric"); - SOCKET_OUT_FLOAT(backfacing, "Backfacing"); - SOCKET_OUT_FLOAT(pointiness, "Pointiness"); + SOCKET_OUT_POINT(position, "Position"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_NORMAL(tangent, "Tangent"); + SOCKET_OUT_NORMAL(true_normal, "True Normal"); + SOCKET_OUT_VECTOR(incoming, "Incoming"); + SOCKET_OUT_POINT(parametric, "Parametric"); + SOCKET_OUT_FLOAT(backfacing, "Backfacing"); + SOCKET_OUT_FLOAT(pointiness, "Pointiness"); - return type; + return type; } -GeometryNode::GeometryNode() -: ShaderNode(node_type) +GeometryNode::GeometryNode() : ShaderNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_GEOMETRY; + special_type = SHADER_SPECIAL_TYPE_GEOMETRY; } void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - if(!output("Tangent")->links.empty()) { - attributes->add(ATTR_STD_GENERATED); - } - if(!output("Pointiness")->links.empty()) { - attributes->add(ATTR_STD_POINTINESS); - } - } - - ShaderNode::attributes(shader, attributes); -} - -void GeometryNode::compile(SVMCompiler& compiler) -{ - ShaderOutput *out; - ShaderNodeType geom_node = NODE_GEOMETRY; - ShaderNodeType attr_node = NODE_ATTR; - - if(bump == SHADER_BUMP_DX) { - geom_node = NODE_GEOMETRY_BUMP_DX; - attr_node = NODE_ATTR_BUMP_DX; - } - else if(bump == SHADER_BUMP_DY) { - geom_node = NODE_GEOMETRY_BUMP_DY; - attr_node = NODE_ATTR_BUMP_DY; - } - - out = output("Position"); - if(!out->links.empty()) { - compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out)); - } - - out = output("Normal"); - if(!out->links.empty()) { - compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out)); - } - - out = output("Tangent"); - if(!out->links.empty()) { - compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out)); - } - - out = output("True Normal"); - if(!out->links.empty()) { - compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out)); - } - - out = output("Incoming"); - if(!out->links.empty()) { - compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out)); - } - - out = output("Parametric"); - if(!out->links.empty()) { - compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out)); - } - - out = output("Backfacing"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out)); - } - - out = output("Pointiness"); - if(!out->links.empty()) { - if(compiler.output_type() != SHADER_TYPE_VOLUME) { - compiler.add_node(attr_node, - ATTR_STD_POINTINESS, - compiler.stack_assign(out), - NODE_ATTR_FLOAT); - } - else { - compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out)); - } - } -} - -void GeometryNode::compile(OSLCompiler& compiler) -{ - if(bump == SHADER_BUMP_DX) - compiler.parameter("bump_offset", "dx"); - else if(bump == SHADER_BUMP_DY) - compiler.parameter("bump_offset", "dy"); - else - compiler.parameter("bump_offset", "center"); - - compiler.add(this, "node_geometry"); + if (shader->has_surface) { + if (!output("Tangent")->links.empty()) { + attributes->add(ATTR_STD_GENERATED); + } + if (!output("Pointiness")->links.empty()) { + attributes->add(ATTR_STD_POINTINESS); + } + } + + ShaderNode::attributes(shader, attributes); +} + +void GeometryNode::compile(SVMCompiler &compiler) +{ + ShaderOutput *out; + ShaderNodeType geom_node = NODE_GEOMETRY; + ShaderNodeType attr_node = NODE_ATTR; + + if (bump == SHADER_BUMP_DX) { + geom_node = NODE_GEOMETRY_BUMP_DX; + attr_node = NODE_ATTR_BUMP_DX; + } + else if (bump == SHADER_BUMP_DY) { + geom_node = NODE_GEOMETRY_BUMP_DY; + attr_node = NODE_ATTR_BUMP_DY; + } + + out = output("Position"); + if (!out->links.empty()) { + compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out)); + } + + out = output("Normal"); + if (!out->links.empty()) { + compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out)); + } + + out = output("Tangent"); + if (!out->links.empty()) { + compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out)); + } + + out = output("True Normal"); + if (!out->links.empty()) { + compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out)); + } + + out = output("Incoming"); + if (!out->links.empty()) { + compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out)); + } + + out = output("Parametric"); + if (!out->links.empty()) { + compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out)); + } + + out = output("Backfacing"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out)); + } + + out = output("Pointiness"); + if (!out->links.empty()) { + if (compiler.output_type() != SHADER_TYPE_VOLUME) { + compiler.add_node( + attr_node, ATTR_STD_POINTINESS, compiler.stack_assign(out), NODE_ATTR_FLOAT); + } + else { + compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out)); + } + } +} + +void GeometryNode::compile(OSLCompiler &compiler) +{ + if (bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if (bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); + + compiler.add(this, "node_geometry"); } int GeometryNode::get_group() { - ShaderOutput *out; - int result = ShaderNode::get_group(); + ShaderOutput *out; + int result = ShaderNode::get_group(); - /* Backfacing uses NODE_LIGHT_PATH */ - out = output("Backfacing"); - if (!out->links.empty()) { - result = max(result, NODE_GROUP_LEVEL_1); - } + /* Backfacing uses NODE_LIGHT_PATH */ + out = output("Backfacing"); + if (!out->links.empty()) { + result = max(result, NODE_GROUP_LEVEL_1); + } - return result; + return result; } /* TextureCoordinate */ NODE_DEFINE(TextureCoordinateNode) { - NodeType* type = NodeType::add("texture_coordinate", create, NodeType::SHADER); + NodeType *type = NodeType::add("texture_coordinate", create, NodeType::SHADER); - SOCKET_BOOLEAN(from_dupli, "From Dupli", false); - SOCKET_BOOLEAN(use_transform, "Use Transform", false); - SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity()); + SOCKET_BOOLEAN(from_dupli, "From Dupli", false); + SOCKET_BOOLEAN(use_transform, "Use Transform", false); + SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity()); - SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_NORMAL(normal_osl, + "NormalIn", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - SOCKET_OUT_POINT(generated, "Generated"); - SOCKET_OUT_NORMAL(normal, "Normal"); - SOCKET_OUT_POINT(UV, "UV"); - SOCKET_OUT_POINT(object, "Object"); - SOCKET_OUT_POINT(camera, "Camera"); - SOCKET_OUT_POINT(window, "Window"); - SOCKET_OUT_NORMAL(reflection, "Reflection"); + SOCKET_OUT_POINT(generated, "Generated"); + SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_POINT(UV, "UV"); + SOCKET_OUT_POINT(object, "Object"); + SOCKET_OUT_POINT(camera, "Camera"); + SOCKET_OUT_POINT(window, "Window"); + SOCKET_OUT_NORMAL(reflection, "Reflection"); - return type; + return type; } -TextureCoordinateNode::TextureCoordinateNode() -: ShaderNode(node_type) +TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(node_type) { } void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - if(!from_dupli) { - if(!output("Generated")->links.empty()) - attributes->add(ATTR_STD_GENERATED); - if(!output("UV")->links.empty()) - attributes->add(ATTR_STD_UV); - } - } - - if(shader->has_volume) { - if(!from_dupli) { - if(!output("Generated")->links.empty()) { - attributes->add(ATTR_STD_GENERATED_TRANSFORM); - } - } - } - - ShaderNode::attributes(shader, attributes); -} - -void TextureCoordinateNode::compile(SVMCompiler& compiler) -{ - ShaderOutput *out; - ShaderNodeType texco_node = NODE_TEX_COORD; - ShaderNodeType attr_node = NODE_ATTR; - ShaderNodeType geom_node = NODE_GEOMETRY; - - if(bump == SHADER_BUMP_DX) { - texco_node = NODE_TEX_COORD_BUMP_DX; - attr_node = NODE_ATTR_BUMP_DX; - geom_node = NODE_GEOMETRY_BUMP_DX; - } - else if(bump == SHADER_BUMP_DY) { - texco_node = NODE_TEX_COORD_BUMP_DY; - attr_node = NODE_ATTR_BUMP_DY; - geom_node = NODE_GEOMETRY_BUMP_DY; - } - - out = output("Generated"); - if(!out->links.empty()) { - if(compiler.background) { - compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out)); - } - else { - if(from_dupli) { - compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out)); - } - else if(compiler.output_type() == SHADER_TYPE_VOLUME) { - compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out)); - } - else { - int attr = compiler.attribute(ATTR_STD_GENERATED); - compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3); - } - } - } - - out = output("Normal"); - if(!out->links.empty()) { - compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out)); - } - - out = output("UV"); - if(!out->links.empty()) { - if(from_dupli) { - compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out)); - } - else { - int attr = compiler.attribute(ATTR_STD_UV); - compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3); - } - } - - out = output("Object"); - if(!out->links.empty()) { - compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform); - if(use_transform) { - Transform ob_itfm = transform_inverse(ob_tfm); - compiler.add_node(ob_itfm.x); - compiler.add_node(ob_itfm.y); - compiler.add_node(ob_itfm.z); - } - } - - out = output("Camera"); - if(!out->links.empty()) { - compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out)); - } - - out = output("Window"); - if(!out->links.empty()) { - compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out)); - } - - out = output("Reflection"); - if(!out->links.empty()) { - if(compiler.background) { - compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out)); - } - else { - compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out)); - } - } -} - -void TextureCoordinateNode::compile(OSLCompiler& compiler) -{ - if(bump == SHADER_BUMP_DX) - compiler.parameter("bump_offset", "dx"); - else if(bump == SHADER_BUMP_DY) - compiler.parameter("bump_offset", "dy"); - else - compiler.parameter("bump_offset", "center"); - - if(compiler.background) - compiler.parameter("is_background", true); - if(compiler.output_type() == SHADER_TYPE_VOLUME) - compiler.parameter("is_volume", true); - compiler.parameter(this, "use_transform"); - Transform ob_itfm = transform_inverse(ob_tfm); - compiler.parameter("object_itfm", ob_itfm); - - compiler.parameter(this, "from_dupli"); - - compiler.add(this, "node_texture_coordinate"); + if (shader->has_surface) { + if (!from_dupli) { + if (!output("Generated")->links.empty()) + attributes->add(ATTR_STD_GENERATED); + if (!output("UV")->links.empty()) + attributes->add(ATTR_STD_UV); + } + } + + if (shader->has_volume) { + if (!from_dupli) { + if (!output("Generated")->links.empty()) { + attributes->add(ATTR_STD_GENERATED_TRANSFORM); + } + } + } + + ShaderNode::attributes(shader, attributes); +} + +void TextureCoordinateNode::compile(SVMCompiler &compiler) +{ + ShaderOutput *out; + ShaderNodeType texco_node = NODE_TEX_COORD; + ShaderNodeType attr_node = NODE_ATTR; + ShaderNodeType geom_node = NODE_GEOMETRY; + + if (bump == SHADER_BUMP_DX) { + texco_node = NODE_TEX_COORD_BUMP_DX; + attr_node = NODE_ATTR_BUMP_DX; + geom_node = NODE_GEOMETRY_BUMP_DX; + } + else if (bump == SHADER_BUMP_DY) { + texco_node = NODE_TEX_COORD_BUMP_DY; + attr_node = NODE_ATTR_BUMP_DY; + geom_node = NODE_GEOMETRY_BUMP_DY; + } + + out = output("Generated"); + if (!out->links.empty()) { + if (compiler.background) { + compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out)); + } + else { + if (from_dupli) { + compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out)); + } + else if (compiler.output_type() == SHADER_TYPE_VOLUME) { + compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out)); + } + else { + int attr = compiler.attribute(ATTR_STD_GENERATED); + compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3); + } + } + } + + out = output("Normal"); + if (!out->links.empty()) { + compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out)); + } + + out = output("UV"); + if (!out->links.empty()) { + if (from_dupli) { + compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out)); + } + else { + int attr = compiler.attribute(ATTR_STD_UV); + compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3); + } + } + + out = output("Object"); + if (!out->links.empty()) { + compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform); + if (use_transform) { + Transform ob_itfm = transform_inverse(ob_tfm); + compiler.add_node(ob_itfm.x); + compiler.add_node(ob_itfm.y); + compiler.add_node(ob_itfm.z); + } + } + + out = output("Camera"); + if (!out->links.empty()) { + compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out)); + } + + out = output("Window"); + if (!out->links.empty()) { + compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out)); + } + + out = output("Reflection"); + if (!out->links.empty()) { + if (compiler.background) { + compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out)); + } + else { + compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out)); + } + } +} + +void TextureCoordinateNode::compile(OSLCompiler &compiler) +{ + if (bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if (bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); + + if (compiler.background) + compiler.parameter("is_background", true); + if (compiler.output_type() == SHADER_TYPE_VOLUME) + compiler.parameter("is_volume", true); + compiler.parameter(this, "use_transform"); + Transform ob_itfm = transform_inverse(ob_tfm); + compiler.parameter("object_itfm", ob_itfm); + + compiler.parameter(this, "from_dupli"); + + compiler.add(this, "node_texture_coordinate"); } /* UV Map */ NODE_DEFINE(UVMapNode) { - NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER); + NodeType *type = NodeType::add("uvmap", create, NodeType::SHADER); - SOCKET_STRING(attribute, "attribute", ustring()); - SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false); + SOCKET_STRING(attribute, "attribute", ustring()); + SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false); - SOCKET_OUT_POINT(UV, "UV"); + SOCKET_OUT_POINT(UV, "UV"); - return type; + return type; } -UVMapNode::UVMapNode() -: ShaderNode(node_type) +UVMapNode::UVMapNode() : ShaderNode(node_type) { } void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - if(!from_dupli) { - if(!output("UV")->links.empty()) { - if(attribute != "") - attributes->add(attribute); - else - attributes->add(ATTR_STD_UV); - } - } - } - - ShaderNode::attributes(shader, attributes); -} - -void UVMapNode::compile(SVMCompiler& compiler) -{ - ShaderOutput *out = output("UV"); - ShaderNodeType texco_node = NODE_TEX_COORD; - ShaderNodeType attr_node = NODE_ATTR; - int attr; - - if(bump == SHADER_BUMP_DX) { - texco_node = NODE_TEX_COORD_BUMP_DX; - attr_node = NODE_ATTR_BUMP_DX; - } - else if(bump == SHADER_BUMP_DY) { - texco_node = NODE_TEX_COORD_BUMP_DY; - attr_node = NODE_ATTR_BUMP_DY; - } - - if(!out->links.empty()) { - if(from_dupli) { - compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out)); - } - else { - if(attribute != "") - attr = compiler.attribute(attribute); - else - attr = compiler.attribute(ATTR_STD_UV); - - compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3); - } - } -} - -void UVMapNode::compile(OSLCompiler& compiler) -{ - if(bump == SHADER_BUMP_DX) - compiler.parameter("bump_offset", "dx"); - else if(bump == SHADER_BUMP_DY) - compiler.parameter("bump_offset", "dy"); - else - compiler.parameter("bump_offset", "center"); - - compiler.parameter(this, "from_dupli"); - compiler.parameter(this, "attribute"); - compiler.add(this, "node_uv_map"); + if (shader->has_surface) { + if (!from_dupli) { + if (!output("UV")->links.empty()) { + if (attribute != "") + attributes->add(attribute); + else + attributes->add(ATTR_STD_UV); + } + } + } + + ShaderNode::attributes(shader, attributes); +} + +void UVMapNode::compile(SVMCompiler &compiler) +{ + ShaderOutput *out = output("UV"); + ShaderNodeType texco_node = NODE_TEX_COORD; + ShaderNodeType attr_node = NODE_ATTR; + int attr; + + if (bump == SHADER_BUMP_DX) { + texco_node = NODE_TEX_COORD_BUMP_DX; + attr_node = NODE_ATTR_BUMP_DX; + } + else if (bump == SHADER_BUMP_DY) { + texco_node = NODE_TEX_COORD_BUMP_DY; + attr_node = NODE_ATTR_BUMP_DY; + } + + if (!out->links.empty()) { + if (from_dupli) { + compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out)); + } + else { + if (attribute != "") + attr = compiler.attribute(attribute); + else + attr = compiler.attribute(ATTR_STD_UV); + + compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3); + } + } +} + +void UVMapNode::compile(OSLCompiler &compiler) +{ + if (bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if (bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); + + compiler.parameter(this, "from_dupli"); + compiler.parameter(this, "attribute"); + compiler.add(this, "node_uv_map"); } /* Light Path */ NODE_DEFINE(LightPathNode) { - NodeType* type = NodeType::add("light_path", create, NodeType::SHADER); + NodeType *type = NodeType::add("light_path", create, NodeType::SHADER); - SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray"); - SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray"); - SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray"); - SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray"); - SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray"); - SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray"); - SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray"); - SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray"); - SOCKET_OUT_FLOAT(ray_length, "Ray Length"); - SOCKET_OUT_FLOAT(ray_depth, "Ray Depth"); - SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth"); - SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth"); - SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth"); - SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth"); + SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray"); + SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray"); + SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray"); + SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray"); + SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray"); + SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray"); + SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray"); + SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray"); + SOCKET_OUT_FLOAT(ray_length, "Ray Length"); + SOCKET_OUT_FLOAT(ray_depth, "Ray Depth"); + SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth"); + SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth"); + SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth"); + SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth"); - return type; + return type; } -LightPathNode::LightPathNode() -: ShaderNode(node_type) +LightPathNode::LightPathNode() : ShaderNode(node_type) { } -void LightPathNode::compile(SVMCompiler& compiler) +void LightPathNode::compile(SVMCompiler &compiler) { - ShaderOutput *out; - - out = output("Is Camera Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out)); - } + ShaderOutput *out; - out = output("Is Shadow Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out)); - } + out = output("Is Camera Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out)); + } - out = output("Is Diffuse Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out)); - } + out = output("Is Shadow Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out)); + } - out = output("Is Glossy Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out)); - } + out = output("Is Diffuse Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out)); + } - out = output("Is Singular Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out)); - } + out = output("Is Glossy Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out)); + } - out = output("Is Reflection Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out)); - } + out = output("Is Singular Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out)); + } + out = output("Is Reflection Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out)); + } - out = output("Is Transmission Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out)); - } + out = output("Is Transmission Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out)); + } - out = output("Is Volume Scatter Ray"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out)); - } + out = output("Is Volume Scatter Ray"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out)); + } - out = output("Ray Length"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out)); - } + out = output("Ray Length"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out)); + } - out = output("Ray Depth"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out)); - } + out = output("Ray Depth"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out)); + } - out = output("Diffuse Depth"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out)); - } + out = output("Diffuse Depth"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out)); + } - out = output("Glossy Depth"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out)); - } + out = output("Glossy Depth"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out)); + } - out = output("Transparent Depth"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out)); - } + out = output("Transparent Depth"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out)); + } - out = output("Transmission Depth"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out)); - } + out = output("Transmission Depth"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out)); + } } -void LightPathNode::compile(OSLCompiler& compiler) +void LightPathNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_light_path"); + compiler.add(this, "node_light_path"); } /* Light Falloff */ NODE_DEFINE(LightFalloffNode) { - NodeType* type = NodeType::add("light_falloff", create, NodeType::SHADER); + NodeType *type = NodeType::add("light_falloff", create, NodeType::SHADER); - SOCKET_IN_FLOAT(strength, "Strength", 100.0f); - SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); + SOCKET_IN_FLOAT(strength, "Strength", 100.0f); + SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f); - SOCKET_OUT_FLOAT(quadratic, "Quadratic"); - SOCKET_OUT_FLOAT(linear, "Linear"); - SOCKET_OUT_FLOAT(constant, "Constant"); + SOCKET_OUT_FLOAT(quadratic, "Quadratic"); + SOCKET_OUT_FLOAT(linear, "Linear"); + SOCKET_OUT_FLOAT(constant, "Constant"); - return type; + return type; } -LightFalloffNode::LightFalloffNode() -: ShaderNode(node_type) +LightFalloffNode::LightFalloffNode() : ShaderNode(node_type) { } -void LightFalloffNode::compile(SVMCompiler& compiler) +void LightFalloffNode::compile(SVMCompiler &compiler) { - ShaderInput *strength_in = input("Strength"); - ShaderInput *smooth_in = input("Smooth"); + ShaderInput *strength_in = input("Strength"); + ShaderInput *smooth_in = input("Smooth"); - ShaderOutput *out = output("Quadratic"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_QUADRATIC, - compiler.encode_uchar4( - compiler.stack_assign(strength_in), - compiler.stack_assign(smooth_in), - compiler.stack_assign(out))); - } + ShaderOutput *out = output("Quadratic"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_FALLOFF, + NODE_LIGHT_FALLOFF_QUADRATIC, + compiler.encode_uchar4(compiler.stack_assign(strength_in), + compiler.stack_assign(smooth_in), + compiler.stack_assign(out))); + } - out = output("Linear"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_LINEAR, - compiler.encode_uchar4( - compiler.stack_assign(strength_in), - compiler.stack_assign(smooth_in), - compiler.stack_assign(out))); - } + out = output("Linear"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_FALLOFF, + NODE_LIGHT_FALLOFF_LINEAR, + compiler.encode_uchar4(compiler.stack_assign(strength_in), + compiler.stack_assign(smooth_in), + compiler.stack_assign(out))); + } - out = output("Constant"); - if(!out->links.empty()) { - compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_CONSTANT, - compiler.encode_uchar4( - compiler.stack_assign(strength_in), - compiler.stack_assign(smooth_in), - compiler.stack_assign(out))); - } + out = output("Constant"); + if (!out->links.empty()) { + compiler.add_node(NODE_LIGHT_FALLOFF, + NODE_LIGHT_FALLOFF_CONSTANT, + compiler.encode_uchar4(compiler.stack_assign(strength_in), + compiler.stack_assign(smooth_in), + compiler.stack_assign(out))); + } } -void LightFalloffNode::compile(OSLCompiler& compiler) +void LightFalloffNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_light_falloff"); + compiler.add(this, "node_light_falloff"); } /* Object Info */ NODE_DEFINE(ObjectInfoNode) { - NodeType* type = NodeType::add("object_info", create, NodeType::SHADER); + NodeType *type = NodeType::add("object_info", create, NodeType::SHADER); - SOCKET_OUT_VECTOR(location, "Location"); - SOCKET_OUT_FLOAT(object_index, "Object Index"); - SOCKET_OUT_FLOAT(material_index, "Material Index"); - SOCKET_OUT_FLOAT(random, "Random"); + SOCKET_OUT_VECTOR(location, "Location"); + SOCKET_OUT_FLOAT(object_index, "Object Index"); + SOCKET_OUT_FLOAT(material_index, "Material Index"); + SOCKET_OUT_FLOAT(random, "Random"); - return type; + return type; } -ObjectInfoNode::ObjectInfoNode() -: ShaderNode(node_type) +ObjectInfoNode::ObjectInfoNode() : ShaderNode(node_type) { } -void ObjectInfoNode::compile(SVMCompiler& compiler) +void ObjectInfoNode::compile(SVMCompiler &compiler) { - ShaderOutput *out = output("Location"); - if(!out->links.empty()) { - compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out)); - } + ShaderOutput *out = output("Location"); + if (!out->links.empty()) { + compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out)); + } - out = output("Object Index"); - if(!out->links.empty()) { - compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out)); - } + out = output("Object Index"); + if (!out->links.empty()) { + compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out)); + } - out = output("Material Index"); - if(!out->links.empty()) { - compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out)); - } + out = output("Material Index"); + if (!out->links.empty()) { + compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out)); + } - out = output("Random"); - if(!out->links.empty()) { - compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out)); - } + out = output("Random"); + if (!out->links.empty()) { + compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out)); + } } -void ObjectInfoNode::compile(OSLCompiler& compiler) +void ObjectInfoNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_object_info"); + compiler.add(this, "node_object_info"); } /* Particle Info */ NODE_DEFINE(ParticleInfoNode) { - NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER); + NodeType *type = NodeType::add("particle_info", create, NodeType::SHADER); - SOCKET_OUT_FLOAT(index, "Index"); - SOCKET_OUT_FLOAT(random, "Random"); - SOCKET_OUT_FLOAT(age, "Age"); - SOCKET_OUT_FLOAT(lifetime, "Lifetime"); - SOCKET_OUT_POINT(location, "Location"); -#if 0 /* not yet supported */ - SOCKET_OUT_QUATERNION(rotation, "Rotation"); + SOCKET_OUT_FLOAT(index, "Index"); + SOCKET_OUT_FLOAT(random, "Random"); + SOCKET_OUT_FLOAT(age, "Age"); + SOCKET_OUT_FLOAT(lifetime, "Lifetime"); + SOCKET_OUT_POINT(location, "Location"); +#if 0 /* not yet supported */ + SOCKET_OUT_QUATERNION(rotation, "Rotation"); #endif - SOCKET_OUT_FLOAT(size, "Size"); - SOCKET_OUT_VECTOR(velocity, "Velocity"); - SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity"); + SOCKET_OUT_FLOAT(size, "Size"); + SOCKET_OUT_VECTOR(velocity, "Velocity"); + SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity"); - return type; + return type; } -ParticleInfoNode::ParticleInfoNode() -: ShaderNode(node_type) +ParticleInfoNode::ParticleInfoNode() : ShaderNode(node_type) { } void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(!output("Index")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); - if(!output("Random")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); - if(!output("Age")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); - if(!output("Lifetime")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); - if(!output("Location")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); -#if 0 /* not yet supported */ - if(!output("Rotation")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); + if (!output("Index")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if (!output("Random")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if (!output("Age")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if (!output("Lifetime")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if (!output("Location")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); +#if 0 /* not yet supported */ + if(!output("Rotation")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); #endif - if(!output("Size")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); - if(!output("Velocity")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); - if(!output("Angular Velocity")->links.empty()) - attributes->add(ATTR_STD_PARTICLE); + if (!output("Size")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if (!output("Velocity")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if (!output("Angular Velocity")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); - ShaderNode::attributes(shader, attributes); + ShaderNode::attributes(shader, attributes); } -void ParticleInfoNode::compile(SVMCompiler& compiler) +void ParticleInfoNode::compile(SVMCompiler &compiler) { - ShaderOutput *out; + ShaderOutput *out; - out = output("Index"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out)); - } + out = output("Index"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out)); + } - out = output("Random"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_RANDOM, compiler.stack_assign(out)); - } + out = output("Random"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_RANDOM, compiler.stack_assign(out)); + } - out = output("Age"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out)); - } + out = output("Age"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out)); + } - out = output("Lifetime"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out)); - } + out = output("Lifetime"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out)); + } - out = output("Location"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out)); - } + out = output("Location"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out)); + } - /* quaternion data is not yet supported by Cycles */ + /* quaternion data is not yet supported by Cycles */ #if 0 - out = output("Rotation"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out)); - } + out = output("Rotation"); + if(!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out)); + } #endif - out = output("Size"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out)); - } + out = output("Size"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out)); + } - out = output("Velocity"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out)); - } + out = output("Velocity"); + if (!out->links.empty()) { + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out)); + } - out = output("Angular Velocity"); - if(!out->links.empty()) { - compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out)); - } + out = output("Angular Velocity"); + if (!out->links.empty()) { + compiler.add_node( + NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out)); + } } -void ParticleInfoNode::compile(OSLCompiler& compiler) +void ParticleInfoNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_particle_info"); + compiler.add(this, "node_particle_info"); } /* Hair Info */ NODE_DEFINE(HairInfoNode) { - NodeType* type = NodeType::add("hair_info", create, NodeType::SHADER); + NodeType *type = NodeType::add("hair_info", create, NodeType::SHADER); - SOCKET_OUT_FLOAT(is_strand, "Is Strand"); - SOCKET_OUT_FLOAT(intercept, "Intercept"); - SOCKET_OUT_FLOAT(thickness, "Thickness"); - SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal"); + SOCKET_OUT_FLOAT(is_strand, "Is Strand"); + SOCKET_OUT_FLOAT(intercept, "Intercept"); + SOCKET_OUT_FLOAT(thickness, "Thickness"); + SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal"); #if 0 /*output for minimum hair width transparency - deactivated */ - SOCKET_OUT_FLOAT(fade, "Fade"); + SOCKET_OUT_FLOAT(fade, "Fade"); #endif - SOCKET_OUT_FLOAT(index, "Random"); + SOCKET_OUT_FLOAT(index, "Random"); - return type; + return type; } -HairInfoNode::HairInfoNode() -: ShaderNode(node_type) +HairInfoNode::HairInfoNode() : ShaderNode(node_type) { } void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - ShaderOutput *intercept_out = output("Intercept"); + if (shader->has_surface) { + ShaderOutput *intercept_out = output("Intercept"); - if(!intercept_out->links.empty()) - attributes->add(ATTR_STD_CURVE_INTERCEPT); + if (!intercept_out->links.empty()) + attributes->add(ATTR_STD_CURVE_INTERCEPT); - if(!output("Random")->links.empty()) - attributes->add(ATTR_STD_CURVE_RANDOM); - } + if (!output("Random")->links.empty()) + attributes->add(ATTR_STD_CURVE_RANDOM); + } - ShaderNode::attributes(shader, attributes); + ShaderNode::attributes(shader, attributes); } -void HairInfoNode::compile(SVMCompiler& compiler) +void HairInfoNode::compile(SVMCompiler &compiler) { - ShaderOutput *out; + ShaderOutput *out; - out = output("Is Strand"); - if(!out->links.empty()) { - compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out)); - } + out = output("Is Strand"); + if (!out->links.empty()) { + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out)); + } - out = output("Intercept"); - if(!out->links.empty()) { - int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT); - compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT); - } + out = output("Intercept"); + if (!out->links.empty()) { + int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT); + compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT); + } - out = output("Thickness"); - if(!out->links.empty()) { - compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out)); - } + out = output("Thickness"); + if (!out->links.empty()) { + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out)); + } - out = output("Tangent Normal"); - if(!out->links.empty()) { - compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out)); - } + out = output("Tangent Normal"); + if (!out->links.empty()) { + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out)); + } - /*out = output("Fade"); - if(!out->links.empty()) { - compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out)); - }*/ + /*out = output("Fade"); + if(!out->links.empty()) { + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out)); + }*/ - out = output("Random"); - if(!out->links.empty()) { - int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM); - compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT); - } + out = output("Random"); + if (!out->links.empty()) { + int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM); + compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT); + } } -void HairInfoNode::compile(OSLCompiler& compiler) +void HairInfoNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_hair_info"); + compiler.add(this, "node_hair_info"); } /* Value */ NODE_DEFINE(ValueNode) { - NodeType* type = NodeType::add("value", create, NodeType::SHADER); + NodeType *type = NodeType::add("value", create, NodeType::SHADER); - SOCKET_FLOAT(value, "Value", 0.0f); - SOCKET_OUT_FLOAT(value, "Value"); + SOCKET_FLOAT(value, "Value", 0.0f); + SOCKET_OUT_FLOAT(value, "Value"); - return type; + return type; } -ValueNode::ValueNode() -: ShaderNode(node_type) +ValueNode::ValueNode() : ShaderNode(node_type) { } -void ValueNode::constant_fold(const ConstantFolder& folder) +void ValueNode::constant_fold(const ConstantFolder &folder) { - folder.make_constant(value); + folder.make_constant(value); } -void ValueNode::compile(SVMCompiler& compiler) +void ValueNode::compile(SVMCompiler &compiler) { - ShaderOutput *val_out = output("Value"); + ShaderOutput *val_out = output("Value"); - compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out)); + compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out)); } -void ValueNode::compile(OSLCompiler& compiler) +void ValueNode::compile(OSLCompiler &compiler) { - compiler.parameter("value_value", value); - compiler.add(this, "node_value"); + compiler.parameter("value_value", value); + compiler.add(this, "node_value"); } /* Color */ NODE_DEFINE(ColorNode) { - NodeType* type = NodeType::add("color", create, NodeType::SHADER); + NodeType *type = NodeType::add("color", create, NodeType::SHADER); - SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -ColorNode::ColorNode() -: ShaderNode(node_type) +ColorNode::ColorNode() : ShaderNode(node_type) { } -void ColorNode::constant_fold(const ConstantFolder& folder) +void ColorNode::constant_fold(const ConstantFolder &folder) { - folder.make_constant(value); + folder.make_constant(value); } -void ColorNode::compile(SVMCompiler& compiler) +void ColorNode::compile(SVMCompiler &compiler) { - ShaderOutput *color_out = output("Color"); + ShaderOutput *color_out = output("Color"); - if(!color_out->links.empty()) { - compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); - compiler.add_node(NODE_VALUE_V, value); - } + if (!color_out->links.empty()) { + compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); + compiler.add_node(NODE_VALUE_V, value); + } } -void ColorNode::compile(OSLCompiler& compiler) +void ColorNode::compile(OSLCompiler &compiler) { - compiler.parameter_color("color_value", value); + compiler.parameter_color("color_value", value); - compiler.add(this, "node_value"); + compiler.add(this, "node_value"); } /* Add Closure */ NODE_DEFINE(AddClosureNode) { - NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER); + NodeType *type = NodeType::add("add_closure", create, NodeType::SHADER); - SOCKET_IN_CLOSURE(closure1, "Closure1"); - SOCKET_IN_CLOSURE(closure2, "Closure2"); - SOCKET_OUT_CLOSURE(closure, "Closure"); + SOCKET_IN_CLOSURE(closure1, "Closure1"); + SOCKET_IN_CLOSURE(closure2, "Closure2"); + SOCKET_OUT_CLOSURE(closure, "Closure"); - return type; + return type; } -AddClosureNode::AddClosureNode() -: ShaderNode(node_type) +AddClosureNode::AddClosureNode() : ShaderNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; + special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; } -void AddClosureNode::compile(SVMCompiler& /*compiler*/) +void AddClosureNode::compile(SVMCompiler & /*compiler*/) { - /* handled in the SVM compiler */ + /* handled in the SVM compiler */ } -void AddClosureNode::compile(OSLCompiler& compiler) +void AddClosureNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_add_closure"); + compiler.add(this, "node_add_closure"); } -void AddClosureNode::constant_fold(const ConstantFolder& folder) +void AddClosureNode::constant_fold(const ConstantFolder &folder) { - ShaderInput *closure1_in = input("Closure1"); - ShaderInput *closure2_in = input("Closure2"); + ShaderInput *closure1_in = input("Closure1"); + ShaderInput *closure2_in = input("Closure2"); - /* remove useless add closures nodes */ - if(!closure1_in->link) { - folder.bypass_or_discard(closure2_in); - } - else if(!closure2_in->link) { - folder.bypass_or_discard(closure1_in); - } + /* remove useless add closures nodes */ + if (!closure1_in->link) { + folder.bypass_or_discard(closure2_in); + } + else if (!closure2_in->link) { + folder.bypass_or_discard(closure1_in); + } } /* Mix Closure */ NODE_DEFINE(MixClosureNode) { - NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER); + NodeType *type = NodeType::add("mix_closure", create, NodeType::SHADER); - SOCKET_IN_FLOAT(fac, "Fac", 0.5f); - SOCKET_IN_CLOSURE(closure1, "Closure1"); - SOCKET_IN_CLOSURE(closure2, "Closure2"); + SOCKET_IN_FLOAT(fac, "Fac", 0.5f); + SOCKET_IN_CLOSURE(closure1, "Closure1"); + SOCKET_IN_CLOSURE(closure2, "Closure2"); - SOCKET_OUT_CLOSURE(closure, "Closure"); + SOCKET_OUT_CLOSURE(closure, "Closure"); - return type; + return type; } -MixClosureNode::MixClosureNode() -: ShaderNode(node_type) +MixClosureNode::MixClosureNode() : ShaderNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; + special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE; } -void MixClosureNode::compile(SVMCompiler& /*compiler*/) +void MixClosureNode::compile(SVMCompiler & /*compiler*/) { - /* handled in the SVM compiler */ + /* handled in the SVM compiler */ } -void MixClosureNode::compile(OSLCompiler& compiler) +void MixClosureNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_mix_closure"); + compiler.add(this, "node_mix_closure"); } -void MixClosureNode::constant_fold(const ConstantFolder& folder) +void MixClosureNode::constant_fold(const ConstantFolder &folder) { - ShaderInput *fac_in = input("Fac"); - ShaderInput *closure1_in = input("Closure1"); - ShaderInput *closure2_in = input("Closure2"); + ShaderInput *fac_in = input("Fac"); + ShaderInput *closure1_in = input("Closure1"); + ShaderInput *closure2_in = input("Closure2"); - /* remove useless mix closures nodes */ - if(closure1_in->link == closure2_in->link) { - folder.bypass_or_discard(closure1_in); - } - /* remove unused mix closure input when factor is 0.0 or 1.0 - * check for closure links and make sure factor link is disconnected */ - else if(!fac_in->link) { - /* factor 0.0 */ - if(fac <= 0.0f) { - folder.bypass_or_discard(closure1_in); - } - /* factor 1.0 */ - else if(fac >= 1.0f) { - folder.bypass_or_discard(closure2_in); - } - } + /* remove useless mix closures nodes */ + if (closure1_in->link == closure2_in->link) { + folder.bypass_or_discard(closure1_in); + } + /* remove unused mix closure input when factor is 0.0 or 1.0 + * check for closure links and make sure factor link is disconnected */ + else if (!fac_in->link) { + /* factor 0.0 */ + if (fac <= 0.0f) { + folder.bypass_or_discard(closure1_in); + } + /* factor 1.0 */ + else if (fac >= 1.0f) { + folder.bypass_or_discard(closure2_in); + } + } } /* Mix Closure */ NODE_DEFINE(MixClosureWeightNode) { - NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER); + NodeType *type = NodeType::add("mix_closure_weight", create, NodeType::SHADER); - SOCKET_IN_FLOAT(weight, "Weight", 1.0f); - SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_FLOAT(weight, "Weight", 1.0f); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); - SOCKET_OUT_FLOAT(weight1, "Weight1"); - SOCKET_OUT_FLOAT(weight2, "Weight2"); + SOCKET_OUT_FLOAT(weight1, "Weight1"); + SOCKET_OUT_FLOAT(weight2, "Weight2"); - return type; + return type; } -MixClosureWeightNode::MixClosureWeightNode() -: ShaderNode(node_type) +MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(node_type) { } -void MixClosureWeightNode::compile(SVMCompiler& compiler) +void MixClosureWeightNode::compile(SVMCompiler &compiler) { - ShaderInput *weight_in = input("Weight"); - ShaderInput *fac_in = input("Fac"); - ShaderOutput *weight1_out = output("Weight1"); - ShaderOutput *weight2_out = output("Weight2"); + ShaderInput *weight_in = input("Weight"); + ShaderInput *fac_in = input("Fac"); + ShaderOutput *weight1_out = output("Weight1"); + ShaderOutput *weight2_out = output("Weight2"); - compiler.add_node(NODE_MIX_CLOSURE, - compiler.encode_uchar4( - compiler.stack_assign(fac_in), - compiler.stack_assign(weight_in), - compiler.stack_assign(weight1_out), - compiler.stack_assign(weight2_out))); + compiler.add_node(NODE_MIX_CLOSURE, + compiler.encode_uchar4(compiler.stack_assign(fac_in), + compiler.stack_assign(weight_in), + compiler.stack_assign(weight1_out), + compiler.stack_assign(weight2_out))); } -void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/) +void MixClosureWeightNode::compile(OSLCompiler & /*compiler*/) { - assert(0); + assert(0); } /* Invert */ NODE_DEFINE(InvertNode) { - NodeType* type = NodeType::add("invert", create, NodeType::SHADER); + NodeType *type = NodeType::add("invert", create, NodeType::SHADER); - SOCKET_IN_FLOAT(fac, "Fac", 1.0f); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -InvertNode::InvertNode() -: ShaderNode(node_type) +InvertNode::InvertNode() : ShaderNode(node_type) { } -void InvertNode::constant_fold(const ConstantFolder& folder) +void InvertNode::constant_fold(const ConstantFolder &folder) { - ShaderInput *fac_in = input("Fac"); - ShaderInput *color_in = input("Color"); + ShaderInput *fac_in = input("Fac"); + ShaderInput *color_in = input("Color"); - if(!fac_in->link) { - /* evaluate fully constant node */ - if(!color_in->link) { - folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); - } - /* remove no-op node */ - else if(fac == 0.0f) { - folder.bypass(color_in->link); - } - } + if (!fac_in->link) { + /* evaluate fully constant node */ + if (!color_in->link) { + folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); + } + /* remove no-op node */ + else if (fac == 0.0f) { + folder.bypass(color_in->link); + } + } } -void InvertNode::compile(SVMCompiler& compiler) +void InvertNode::compile(SVMCompiler &compiler) { - ShaderInput *fac_in = input("Fac"); - ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); + ShaderInput *fac_in = input("Fac"); + ShaderInput *color_in = input("Color"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_INVERT, - compiler.stack_assign(fac_in), - compiler.stack_assign(color_in), - compiler.stack_assign(color_out)); + compiler.add_node(NODE_INVERT, + compiler.stack_assign(fac_in), + compiler.stack_assign(color_in), + compiler.stack_assign(color_out)); } -void InvertNode::compile(OSLCompiler& compiler) +void InvertNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_invert"); + compiler.add(this, "node_invert"); } /* Mix */ NODE_DEFINE(MixNode) { - NodeType* type = NodeType::add("mix", create, NodeType::SHADER); + NodeType *type = NodeType::add("mix", create, NodeType::SHADER); - static NodeEnum type_enum; - type_enum.insert("mix", NODE_MIX_BLEND); - type_enum.insert("add", NODE_MIX_ADD); - type_enum.insert("multiply", NODE_MIX_MUL); - type_enum.insert("screen", NODE_MIX_SCREEN); - type_enum.insert("overlay", NODE_MIX_OVERLAY); - type_enum.insert("subtract", NODE_MIX_SUB); - type_enum.insert("divide", NODE_MIX_DIV); - type_enum.insert("difference", NODE_MIX_DIFF); - type_enum.insert("darken", NODE_MIX_DARK); - type_enum.insert("lighten", NODE_MIX_LIGHT); - type_enum.insert("dodge", NODE_MIX_DODGE); - type_enum.insert("burn", NODE_MIX_BURN); - type_enum.insert("hue", NODE_MIX_HUE); - type_enum.insert("saturation", NODE_MIX_SAT); - type_enum.insert("value", NODE_MIX_VAL); - type_enum.insert("color", NODE_MIX_COLOR); - type_enum.insert("soft_light", NODE_MIX_SOFT); - type_enum.insert("linear_light", NODE_MIX_LINEAR); - SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND); + static NodeEnum type_enum; + type_enum.insert("mix", NODE_MIX_BLEND); + type_enum.insert("add", NODE_MIX_ADD); + type_enum.insert("multiply", NODE_MIX_MUL); + type_enum.insert("screen", NODE_MIX_SCREEN); + type_enum.insert("overlay", NODE_MIX_OVERLAY); + type_enum.insert("subtract", NODE_MIX_SUB); + type_enum.insert("divide", NODE_MIX_DIV); + type_enum.insert("difference", NODE_MIX_DIFF); + type_enum.insert("darken", NODE_MIX_DARK); + type_enum.insert("lighten", NODE_MIX_LIGHT); + type_enum.insert("dodge", NODE_MIX_DODGE); + type_enum.insert("burn", NODE_MIX_BURN); + type_enum.insert("hue", NODE_MIX_HUE); + type_enum.insert("saturation", NODE_MIX_SAT); + type_enum.insert("value", NODE_MIX_VAL); + type_enum.insert("color", NODE_MIX_COLOR); + type_enum.insert("soft_light", NODE_MIX_SOFT); + type_enum.insert("linear_light", NODE_MIX_LINEAR); + SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND); - SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); - SOCKET_IN_FLOAT(fac, "Fac", 0.5f); - SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(fac, "Fac", 0.5f); + SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -MixNode::MixNode() -: ShaderNode(node_type) +MixNode::MixNode() : ShaderNode(node_type) { } -void MixNode::compile(SVMCompiler& compiler) +void MixNode::compile(SVMCompiler &compiler) { - ShaderInput *fac_in = input("Fac"); - ShaderInput *color1_in = input("Color1"); - ShaderInput *color2_in = input("Color2"); - ShaderOutput *color_out = output("Color"); + ShaderInput *fac_in = input("Fac"); + ShaderInput *color1_in = input("Color1"); + ShaderInput *color2_in = input("Color2"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_MIX, - compiler.stack_assign(fac_in), - compiler.stack_assign(color1_in), - compiler.stack_assign(color2_in)); - compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out)); + compiler.add_node(NODE_MIX, + compiler.stack_assign(fac_in), + compiler.stack_assign(color1_in), + compiler.stack_assign(color2_in)); + compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out)); - if(use_clamp) { - compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out)); - compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out)); - } + if (use_clamp) { + compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out)); + compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out)); + } } -void MixNode::compile(OSLCompiler& compiler) +void MixNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "type"); - compiler.parameter(this, "use_clamp"); - compiler.add(this, "node_mix"); + compiler.parameter(this, "type"); + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix"); } -void MixNode::constant_fold(const ConstantFolder& folder) +void MixNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); - } - else { - folder.fold_mix(type, use_clamp); - } + if (folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); + } + else { + folder.fold_mix(type, use_clamp); + } } /* Combine RGB */ NODE_DEFINE(CombineRGBNode) { - NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER); + NodeType *type = NodeType::add("combine_rgb", create, NodeType::SHADER); - SOCKET_IN_FLOAT(r, "R", 0.0f); - SOCKET_IN_FLOAT(g, "G", 0.0f); - SOCKET_IN_FLOAT(b, "B", 0.0f); + SOCKET_IN_FLOAT(r, "R", 0.0f); + SOCKET_IN_FLOAT(g, "G", 0.0f); + SOCKET_IN_FLOAT(b, "B", 0.0f); - SOCKET_OUT_COLOR(image, "Image"); + SOCKET_OUT_COLOR(image, "Image"); - return type; + return type; } -CombineRGBNode::CombineRGBNode() -: ShaderNode(node_type) +CombineRGBNode::CombineRGBNode() : ShaderNode(node_type) { } -void CombineRGBNode::constant_fold(const ConstantFolder& folder) +void CombineRGBNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant(make_float3(r, g, b)); - } + if (folder.all_inputs_constant()) { + folder.make_constant(make_float3(r, g, b)); + } } -void CombineRGBNode::compile(SVMCompiler& compiler) +void CombineRGBNode::compile(SVMCompiler &compiler) { - ShaderInput *red_in = input("R"); - ShaderInput *green_in = input("G"); - ShaderInput *blue_in = input("B"); - ShaderOutput *color_out = output("Image"); + ShaderInput *red_in = input("R"); + ShaderInput *green_in = input("G"); + ShaderInput *blue_in = input("B"); + ShaderOutput *color_out = output("Image"); - compiler.add_node(NODE_COMBINE_VECTOR, - compiler.stack_assign(red_in), 0, - compiler.stack_assign(color_out)); + compiler.add_node( + NODE_COMBINE_VECTOR, compiler.stack_assign(red_in), 0, compiler.stack_assign(color_out)); - compiler.add_node(NODE_COMBINE_VECTOR, - compiler.stack_assign(green_in), 1, - compiler.stack_assign(color_out)); + compiler.add_node( + NODE_COMBINE_VECTOR, compiler.stack_assign(green_in), 1, compiler.stack_assign(color_out)); - compiler.add_node(NODE_COMBINE_VECTOR, - compiler.stack_assign(blue_in), 2, - compiler.stack_assign(color_out)); + compiler.add_node( + NODE_COMBINE_VECTOR, compiler.stack_assign(blue_in), 2, compiler.stack_assign(color_out)); } -void CombineRGBNode::compile(OSLCompiler& compiler) +void CombineRGBNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_combine_rgb"); + compiler.add(this, "node_combine_rgb"); } /* Combine XYZ */ NODE_DEFINE(CombineXYZNode) { - NodeType* type = NodeType::add("combine_xyz", create, NodeType::SHADER); + NodeType *type = NodeType::add("combine_xyz", create, NodeType::SHADER); - SOCKET_IN_FLOAT(x, "X", 0.0f); - SOCKET_IN_FLOAT(y, "Y", 0.0f); - SOCKET_IN_FLOAT(z, "Z", 0.0f); + SOCKET_IN_FLOAT(x, "X", 0.0f); + SOCKET_IN_FLOAT(y, "Y", 0.0f); + SOCKET_IN_FLOAT(z, "Z", 0.0f); - SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_OUT_VECTOR(vector, "Vector"); - return type; + return type; } -CombineXYZNode::CombineXYZNode() -: ShaderNode(node_type) +CombineXYZNode::CombineXYZNode() : ShaderNode(node_type) { } -void CombineXYZNode::constant_fold(const ConstantFolder& folder) +void CombineXYZNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant(make_float3(x, y, z)); - } + if (folder.all_inputs_constant()) { + folder.make_constant(make_float3(x, y, z)); + } } -void CombineXYZNode::compile(SVMCompiler& compiler) +void CombineXYZNode::compile(SVMCompiler &compiler) { - ShaderInput *x_in = input("X"); - ShaderInput *y_in = input("Y"); - ShaderInput *z_in = input("Z"); - ShaderOutput *vector_out = output("Vector"); + ShaderInput *x_in = input("X"); + ShaderInput *y_in = input("Y"); + ShaderInput *z_in = input("Z"); + ShaderOutput *vector_out = output("Vector"); - compiler.add_node(NODE_COMBINE_VECTOR, - compiler.stack_assign(x_in), 0, - compiler.stack_assign(vector_out)); + compiler.add_node( + NODE_COMBINE_VECTOR, compiler.stack_assign(x_in), 0, compiler.stack_assign(vector_out)); - compiler.add_node(NODE_COMBINE_VECTOR, - compiler.stack_assign(y_in), 1, - compiler.stack_assign(vector_out)); + compiler.add_node( + NODE_COMBINE_VECTOR, compiler.stack_assign(y_in), 1, compiler.stack_assign(vector_out)); - compiler.add_node(NODE_COMBINE_VECTOR, - compiler.stack_assign(z_in), 2, - compiler.stack_assign(vector_out)); + compiler.add_node( + NODE_COMBINE_VECTOR, compiler.stack_assign(z_in), 2, compiler.stack_assign(vector_out)); } -void CombineXYZNode::compile(OSLCompiler& compiler) +void CombineXYZNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_combine_xyz"); + compiler.add(this, "node_combine_xyz"); } /* Combine HSV */ NODE_DEFINE(CombineHSVNode) { - NodeType* type = NodeType::add("combine_hsv", create, NodeType::SHADER); + NodeType *type = NodeType::add("combine_hsv", create, NodeType::SHADER); - SOCKET_IN_FLOAT(h, "H", 0.0f); - SOCKET_IN_FLOAT(s, "S", 0.0f); - SOCKET_IN_FLOAT(v, "V", 0.0f); + SOCKET_IN_FLOAT(h, "H", 0.0f); + SOCKET_IN_FLOAT(s, "S", 0.0f); + SOCKET_IN_FLOAT(v, "V", 0.0f); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -CombineHSVNode::CombineHSVNode() -: ShaderNode(node_type) +CombineHSVNode::CombineHSVNode() : ShaderNode(node_type) { } -void CombineHSVNode::constant_fold(const ConstantFolder& folder) +void CombineHSVNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); - } + if (folder.all_inputs_constant()) { + folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); + } } -void CombineHSVNode::compile(SVMCompiler& compiler) +void CombineHSVNode::compile(SVMCompiler &compiler) { - ShaderInput *hue_in = input("H"); - ShaderInput *saturation_in = input("S"); - ShaderInput *value_in = input("V"); - ShaderOutput *color_out = output("Color"); + ShaderInput *hue_in = input("H"); + ShaderInput *saturation_in = input("S"); + ShaderInput *value_in = input("V"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_COMBINE_HSV, - compiler.stack_assign(hue_in), - compiler.stack_assign(saturation_in), - compiler.stack_assign(value_in)); - compiler.add_node(NODE_COMBINE_HSV, - compiler.stack_assign(color_out)); + compiler.add_node(NODE_COMBINE_HSV, + compiler.stack_assign(hue_in), + compiler.stack_assign(saturation_in), + compiler.stack_assign(value_in)); + compiler.add_node(NODE_COMBINE_HSV, compiler.stack_assign(color_out)); } -void CombineHSVNode::compile(OSLCompiler& compiler) +void CombineHSVNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_combine_hsv"); + compiler.add(this, "node_combine_hsv"); } /* Gamma */ NODE_DEFINE(GammaNode) { - NodeType* type = NodeType::add("gamma", create, NodeType::SHADER); + NodeType *type = NodeType::add("gamma", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -GammaNode::GammaNode() -: ShaderNode(node_type) +GammaNode::GammaNode() : ShaderNode(node_type) { } -void GammaNode::constant_fold(const ConstantFolder& folder) +void GammaNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant(svm_math_gamma_color(color, gamma)); - } - else { - ShaderInput *color_in = input("Color"); - ShaderInput *gamma_in = input("Gamma"); + if (folder.all_inputs_constant()) { + folder.make_constant(svm_math_gamma_color(color, gamma)); + } + else { + ShaderInput *color_in = input("Color"); + ShaderInput *gamma_in = input("Gamma"); - /* 1 ^ X == X ^ 0 == 1 */ - if(folder.is_one(color_in) || folder.is_zero(gamma_in)) { - folder.make_one(); - } - /* X ^ 1 == X */ - else if(folder.is_one(gamma_in)) { - folder.try_bypass_or_make_constant(color_in, false); - } - } + /* 1 ^ X == X ^ 0 == 1 */ + if (folder.is_one(color_in) || folder.is_zero(gamma_in)) { + folder.make_one(); + } + /* X ^ 1 == X */ + else if (folder.is_one(gamma_in)) { + folder.try_bypass_or_make_constant(color_in, false); + } + } } -void GammaNode::compile(SVMCompiler& compiler) +void GammaNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Color"); - ShaderInput *gamma_in = input("Gamma"); - ShaderOutput *color_out = output("Color"); + ShaderInput *color_in = input("Color"); + ShaderInput *gamma_in = input("Gamma"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_GAMMA, - compiler.stack_assign(gamma_in), - compiler.stack_assign(color_in), - compiler.stack_assign(color_out)); + compiler.add_node(NODE_GAMMA, + compiler.stack_assign(gamma_in), + compiler.stack_assign(color_in), + compiler.stack_assign(color_out)); } -void GammaNode::compile(OSLCompiler& compiler) +void GammaNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_gamma"); + compiler.add(this, "node_gamma"); } /* Bright Contrast */ NODE_DEFINE(BrightContrastNode) { - NodeType* type = NodeType::add("brightness_contrast", create, NodeType::SHADER); + NodeType *type = NodeType::add("brightness_contrast", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_FLOAT(bright, "Bright", 0.0f); - SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(bright, "Bright", 0.0f); + SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -BrightContrastNode::BrightContrastNode() -: ShaderNode(node_type) +BrightContrastNode::BrightContrastNode() : ShaderNode(node_type) { } -void BrightContrastNode::constant_fold(const ConstantFolder& folder) +void BrightContrastNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant(svm_brightness_contrast(color, bright, contrast)); - } + if (folder.all_inputs_constant()) { + folder.make_constant(svm_brightness_contrast(color, bright, contrast)); + } } -void BrightContrastNode::compile(SVMCompiler& compiler) +void BrightContrastNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Color"); - ShaderInput *bright_in = input("Bright"); - ShaderInput *contrast_in = input("Contrast"); - ShaderOutput *color_out = output("Color"); + ShaderInput *color_in = input("Color"); + ShaderInput *bright_in = input("Bright"); + ShaderInput *contrast_in = input("Contrast"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_BRIGHTCONTRAST, - compiler.stack_assign(color_in), - compiler.stack_assign(color_out), - compiler.encode_uchar4( - compiler.stack_assign(bright_in), - compiler.stack_assign(contrast_in))); + compiler.add_node(NODE_BRIGHTCONTRAST, + compiler.stack_assign(color_in), + compiler.stack_assign(color_out), + compiler.encode_uchar4(compiler.stack_assign(bright_in), + compiler.stack_assign(contrast_in))); } -void BrightContrastNode::compile(OSLCompiler& compiler) +void BrightContrastNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_brightness"); + compiler.add(this, "node_brightness"); } /* Separate RGB */ NODE_DEFINE(SeparateRGBNode) { - NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER); + NodeType *type = NodeType::add("separate_rgb", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_FLOAT(r, "R"); - SOCKET_OUT_FLOAT(g, "G"); - SOCKET_OUT_FLOAT(b, "B"); + SOCKET_OUT_FLOAT(r, "R"); + SOCKET_OUT_FLOAT(g, "G"); + SOCKET_OUT_FLOAT(b, "B"); - return type; + return type; } -SeparateRGBNode::SeparateRGBNode() -: ShaderNode(node_type) +SeparateRGBNode::SeparateRGBNode() : ShaderNode(node_type) { } -void SeparateRGBNode::constant_fold(const ConstantFolder& folder) +void SeparateRGBNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == folder.output) { - folder.make_constant(color[channel]); - return; - } - } - } + if (folder.all_inputs_constant()) { + for (int channel = 0; channel < 3; channel++) { + if (outputs[channel] == folder.output) { + folder.make_constant(color[channel]); + return; + } + } + } } -void SeparateRGBNode::compile(SVMCompiler& compiler) +void SeparateRGBNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Image"); - ShaderOutput *red_out = output("R"); - ShaderOutput *green_out = output("G"); - ShaderOutput *blue_out = output("B"); + ShaderInput *color_in = input("Image"); + ShaderOutput *red_out = output("R"); + ShaderOutput *green_out = output("G"); + ShaderOutput *blue_out = output("B"); - compiler.add_node(NODE_SEPARATE_VECTOR, - compiler.stack_assign(color_in), 0, - compiler.stack_assign(red_out)); + compiler.add_node( + NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 0, compiler.stack_assign(red_out)); - compiler.add_node(NODE_SEPARATE_VECTOR, - compiler.stack_assign(color_in), 1, - compiler.stack_assign(green_out)); + compiler.add_node( + NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 1, compiler.stack_assign(green_out)); - compiler.add_node(NODE_SEPARATE_VECTOR, - compiler.stack_assign(color_in), 2, - compiler.stack_assign(blue_out)); + compiler.add_node( + NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 2, compiler.stack_assign(blue_out)); } -void SeparateRGBNode::compile(OSLCompiler& compiler) +void SeparateRGBNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_separate_rgb"); + compiler.add(this, "node_separate_rgb"); } /* Separate XYZ */ NODE_DEFINE(SeparateXYZNode) { - NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER); + NodeType *type = NodeType::add("separate_xyz", create, NodeType::SHADER); - SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_FLOAT(x, "X"); - SOCKET_OUT_FLOAT(y, "Y"); - SOCKET_OUT_FLOAT(z, "Z"); + SOCKET_OUT_FLOAT(x, "X"); + SOCKET_OUT_FLOAT(y, "Y"); + SOCKET_OUT_FLOAT(z, "Z"); - return type; + return type; } -SeparateXYZNode::SeparateXYZNode() -: ShaderNode(node_type) +SeparateXYZNode::SeparateXYZNode() : ShaderNode(node_type) { } -void SeparateXYZNode::constant_fold(const ConstantFolder& folder) +void SeparateXYZNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == folder.output) { - folder.make_constant(vector[channel]); - return; - } - } - } + if (folder.all_inputs_constant()) { + for (int channel = 0; channel < 3; channel++) { + if (outputs[channel] == folder.output) { + folder.make_constant(vector[channel]); + return; + } + } + } } -void SeparateXYZNode::compile(SVMCompiler& compiler) +void SeparateXYZNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderOutput *x_out = output("X"); - ShaderOutput *y_out = output("Y"); - ShaderOutput *z_out = output("Z"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *x_out = output("X"); + ShaderOutput *y_out = output("Y"); + ShaderOutput *z_out = output("Z"); - compiler.add_node(NODE_SEPARATE_VECTOR, - compiler.stack_assign(vector_in), 0, - compiler.stack_assign(x_out)); + compiler.add_node( + NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 0, compiler.stack_assign(x_out)); - compiler.add_node(NODE_SEPARATE_VECTOR, - compiler.stack_assign(vector_in), 1, - compiler.stack_assign(y_out)); + compiler.add_node( + NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 1, compiler.stack_assign(y_out)); - compiler.add_node(NODE_SEPARATE_VECTOR, - compiler.stack_assign(vector_in), 2, - compiler.stack_assign(z_out)); + compiler.add_node( + NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 2, compiler.stack_assign(z_out)); } -void SeparateXYZNode::compile(OSLCompiler& compiler) +void SeparateXYZNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_separate_xyz"); + compiler.add(this, "node_separate_xyz"); } /* Separate HSV */ NODE_DEFINE(SeparateHSVNode) { - NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER); + NodeType *type = NodeType::add("separate_hsv", create, NodeType::SHADER); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_FLOAT(h, "H"); - SOCKET_OUT_FLOAT(s, "S"); - SOCKET_OUT_FLOAT(v, "V"); + SOCKET_OUT_FLOAT(h, "H"); + SOCKET_OUT_FLOAT(s, "S"); + SOCKET_OUT_FLOAT(v, "V"); - return type; + return type; } -SeparateHSVNode::SeparateHSVNode() -: ShaderNode(node_type) +SeparateHSVNode::SeparateHSVNode() : ShaderNode(node_type) { } -void SeparateHSVNode::constant_fold(const ConstantFolder& folder) +void SeparateHSVNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - float3 hsv = rgb_to_hsv(color); + if (folder.all_inputs_constant()) { + float3 hsv = rgb_to_hsv(color); - for(int channel = 0; channel < 3; channel++) { - if(outputs[channel] == folder.output) { - folder.make_constant(hsv[channel]); - return; - } - } - } + for (int channel = 0; channel < 3; channel++) { + if (outputs[channel] == folder.output) { + folder.make_constant(hsv[channel]); + return; + } + } + } } -void SeparateHSVNode::compile(SVMCompiler& compiler) +void SeparateHSVNode::compile(SVMCompiler &compiler) { - ShaderInput *color_in = input("Color"); - ShaderOutput *hue_out = output("H"); - ShaderOutput *saturation_out = output("S"); - ShaderOutput *value_out = output("V"); + ShaderInput *color_in = input("Color"); + ShaderOutput *hue_out = output("H"); + ShaderOutput *saturation_out = output("S"); + ShaderOutput *value_out = output("V"); - compiler.add_node(NODE_SEPARATE_HSV, - compiler.stack_assign(color_in), - compiler.stack_assign(hue_out), - compiler.stack_assign(saturation_out)); - compiler.add_node(NODE_SEPARATE_HSV, - compiler.stack_assign(value_out)); + compiler.add_node(NODE_SEPARATE_HSV, + compiler.stack_assign(color_in), + compiler.stack_assign(hue_out), + compiler.stack_assign(saturation_out)); + compiler.add_node(NODE_SEPARATE_HSV, compiler.stack_assign(value_out)); } -void SeparateHSVNode::compile(OSLCompiler& compiler) +void SeparateHSVNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_separate_hsv"); + compiler.add(this, "node_separate_hsv"); } /* Hue Saturation Value */ NODE_DEFINE(HSVNode) { - NodeType* type = NodeType::add("hsv", create, NodeType::SHADER); + NodeType *type = NodeType::add("hsv", create, NodeType::SHADER); - SOCKET_IN_FLOAT(hue, "Hue", 0.5f); - SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f); - SOCKET_IN_FLOAT(value, "Value", 1.0f); - SOCKET_IN_FLOAT(fac, "Fac", 1.0f); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(hue, "Hue", 0.5f); + SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f); + SOCKET_IN_FLOAT(value, "Value", 1.0f); + SOCKET_IN_FLOAT(fac, "Fac", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -HSVNode::HSVNode() -: ShaderNode(node_type) +HSVNode::HSVNode() : ShaderNode(node_type) { } -void HSVNode::compile(SVMCompiler& compiler) +void HSVNode::compile(SVMCompiler &compiler) { - ShaderInput *hue_in = input("Hue"); - ShaderInput *saturation_in = input("Saturation"); - ShaderInput *value_in = input("Value"); - ShaderInput *fac_in = input("Fac"); - ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); + ShaderInput *hue_in = input("Hue"); + ShaderInput *saturation_in = input("Saturation"); + ShaderInput *value_in = input("Value"); + ShaderInput *fac_in = input("Fac"); + ShaderInput *color_in = input("Color"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_HSV, - compiler.encode_uchar4( - compiler.stack_assign(color_in), - compiler.stack_assign(fac_in), - compiler.stack_assign(color_out)), - compiler.encode_uchar4( - compiler.stack_assign(hue_in), - compiler.stack_assign(saturation_in), - compiler.stack_assign(value_in))); + compiler.add_node(NODE_HSV, + compiler.encode_uchar4(compiler.stack_assign(color_in), + compiler.stack_assign(fac_in), + compiler.stack_assign(color_out)), + compiler.encode_uchar4(compiler.stack_assign(hue_in), + compiler.stack_assign(saturation_in), + compiler.stack_assign(value_in))); } -void HSVNode::compile(OSLCompiler& compiler) +void HSVNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_hsv"); + compiler.add(this, "node_hsv"); } /* Attribute */ NODE_DEFINE(AttributeNode) { - NodeType* type = NodeType::add("attribute", create, NodeType::SHADER); + NodeType *type = NodeType::add("attribute", create, NodeType::SHADER); - SOCKET_STRING(attribute, "Attribute", ustring()); + SOCKET_STRING(attribute, "Attribute", ustring()); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_VECTOR(vector, "Vector"); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -AttributeNode::AttributeNode() -: ShaderNode(node_type) +AttributeNode::AttributeNode() : ShaderNode(node_type) { } void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - ShaderOutput *color_out = output("Color"); - ShaderOutput *vector_out = output("Vector"); - ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *vector_out = output("Vector"); + ShaderOutput *fac_out = output("Fac"); - if(!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) { - attributes->add_standard(attribute); - } + if (!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) { + attributes->add_standard(attribute); + } - if(shader->has_volume) { - attributes->add(ATTR_STD_GENERATED_TRANSFORM); - } + if (shader->has_volume) { + attributes->add(ATTR_STD_GENERATED_TRANSFORM); + } - ShaderNode::attributes(shader, attributes); + ShaderNode::attributes(shader, attributes); } -void AttributeNode::compile(SVMCompiler& compiler) +void AttributeNode::compile(SVMCompiler &compiler) { - ShaderOutput *color_out = output("Color"); - ShaderOutput *vector_out = output("Vector"); - ShaderOutput *fac_out = output("Fac"); - ShaderNodeType attr_node = NODE_ATTR; - int attr = compiler.attribute_standard(attribute); + ShaderOutput *color_out = output("Color"); + ShaderOutput *vector_out = output("Vector"); + ShaderOutput *fac_out = output("Fac"); + ShaderNodeType attr_node = NODE_ATTR; + int attr = compiler.attribute_standard(attribute); - if(bump == SHADER_BUMP_DX) - attr_node = NODE_ATTR_BUMP_DX; - else if(bump == SHADER_BUMP_DY) - attr_node = NODE_ATTR_BUMP_DY; + if (bump == SHADER_BUMP_DX) + attr_node = NODE_ATTR_BUMP_DX; + else if (bump == SHADER_BUMP_DY) + attr_node = NODE_ATTR_BUMP_DY; - if(!color_out->links.empty() || !vector_out->links.empty()) { - if(!color_out->links.empty()) { - compiler.add_node(attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_FLOAT3); - } - if(!vector_out->links.empty()) { - compiler.add_node(attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_FLOAT3); - } - } + if (!color_out->links.empty() || !vector_out->links.empty()) { + if (!color_out->links.empty()) { + compiler.add_node(attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_FLOAT3); + } + if (!vector_out->links.empty()) { + compiler.add_node(attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_FLOAT3); + } + } - if(!fac_out->links.empty()) { - compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_FLOAT); - } + if (!fac_out->links.empty()) { + compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_FLOAT); + } } -void AttributeNode::compile(OSLCompiler& compiler) +void AttributeNode::compile(OSLCompiler &compiler) { - if(bump == SHADER_BUMP_DX) - compiler.parameter("bump_offset", "dx"); - else if(bump == SHADER_BUMP_DY) - compiler.parameter("bump_offset", "dy"); - else - compiler.parameter("bump_offset", "center"); + if (bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if (bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); - if(Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE) - compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str()); - else - compiler.parameter("name", attribute.c_str()); + if (Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE) + compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str()); + else + compiler.parameter("name", attribute.c_str()); - compiler.add(this, "node_attribute"); + compiler.add(this, "node_attribute"); } /* Camera */ NODE_DEFINE(CameraNode) { - NodeType* type = NodeType::add("camera_info", create, NodeType::SHADER); + NodeType *type = NodeType::add("camera_info", create, NodeType::SHADER); - SOCKET_OUT_VECTOR(view_vector, "View Vector"); - SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth"); - SOCKET_OUT_FLOAT(view_distance, "View Distance"); + SOCKET_OUT_VECTOR(view_vector, "View Vector"); + SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth"); + SOCKET_OUT_FLOAT(view_distance, "View Distance"); - return type; + return type; } -CameraNode::CameraNode() -: ShaderNode(node_type) +CameraNode::CameraNode() : ShaderNode(node_type) { } -void CameraNode::compile(SVMCompiler& compiler) +void CameraNode::compile(SVMCompiler &compiler) { - ShaderOutput *vector_out = output("View Vector"); - ShaderOutput *z_depth_out = output("View Z Depth"); - ShaderOutput *distance_out = output("View Distance"); + ShaderOutput *vector_out = output("View Vector"); + ShaderOutput *z_depth_out = output("View Z Depth"); + ShaderOutput *distance_out = output("View Distance"); - compiler.add_node(NODE_CAMERA, - compiler.stack_assign(vector_out), - compiler.stack_assign(z_depth_out), - compiler.stack_assign(distance_out)); + compiler.add_node(NODE_CAMERA, + compiler.stack_assign(vector_out), + compiler.stack_assign(z_depth_out), + compiler.stack_assign(distance_out)); } -void CameraNode::compile(OSLCompiler& compiler) +void CameraNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_camera"); + compiler.add(this, "node_camera"); } /* Fresnel */ NODE_DEFINE(FresnelNode) { - NodeType* type = NodeType::add("fresnel", create, NodeType::SHADER); + NodeType *type = NodeType::add("fresnel", create, NodeType::SHADER); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - SOCKET_IN_FLOAT(IOR, "IOR", 1.45f); + SOCKET_IN_NORMAL(normal, + "Normal", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(IOR, "IOR", 1.45f); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -FresnelNode::FresnelNode() -: ShaderNode(node_type) +FresnelNode::FresnelNode() : ShaderNode(node_type) { } -void FresnelNode::compile(SVMCompiler& compiler) +void FresnelNode::compile(SVMCompiler &compiler) { - ShaderInput *normal_in = input("Normal"); - ShaderInput *IOR_in = input("IOR"); - ShaderOutput *fac_out = output("Fac"); + ShaderInput *normal_in = input("Normal"); + ShaderInput *IOR_in = input("IOR"); + ShaderOutput *fac_out = output("Fac"); - compiler.add_node(NODE_FRESNEL, - compiler.stack_assign(IOR_in), - __float_as_int(IOR), - compiler.encode_uchar4( - compiler.stack_assign_if_linked(normal_in), - compiler.stack_assign(fac_out))); + compiler.add_node(NODE_FRESNEL, + compiler.stack_assign(IOR_in), + __float_as_int(IOR), + compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(fac_out))); } -void FresnelNode::compile(OSLCompiler& compiler) +void FresnelNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_fresnel"); + compiler.add(this, "node_fresnel"); } /* Layer Weight */ NODE_DEFINE(LayerWeightNode) { - NodeType* type = NodeType::add("layer_weight", create, NodeType::SHADER); + NodeType *type = NodeType::add("layer_weight", create, NodeType::SHADER); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - SOCKET_IN_FLOAT(blend, "Blend", 0.5f); + SOCKET_IN_NORMAL(normal, + "Normal", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(blend, "Blend", 0.5f); - SOCKET_OUT_FLOAT(fresnel, "Fresnel"); - SOCKET_OUT_FLOAT(facing, "Facing"); + SOCKET_OUT_FLOAT(fresnel, "Fresnel"); + SOCKET_OUT_FLOAT(facing, "Facing"); - return type; + return type; } -LayerWeightNode::LayerWeightNode() -: ShaderNode(node_type) +LayerWeightNode::LayerWeightNode() : ShaderNode(node_type) { } -void LayerWeightNode::compile(SVMCompiler& compiler) +void LayerWeightNode::compile(SVMCompiler &compiler) { - ShaderInput *normal_in = input("Normal"); - ShaderInput *blend_in = input("Blend"); - ShaderOutput *fresnel_out = output("Fresnel"); - ShaderOutput *facing_out = output("Facing"); + ShaderInput *normal_in = input("Normal"); + ShaderInput *blend_in = input("Blend"); + ShaderOutput *fresnel_out = output("Fresnel"); + ShaderOutput *facing_out = output("Facing"); - if(!fresnel_out->links.empty()) { - compiler.add_node(NODE_LAYER_WEIGHT, - compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend), - compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, - compiler.stack_assign_if_linked(normal_in), - compiler.stack_assign(fresnel_out))); - } + if (!fresnel_out->links.empty()) { + compiler.add_node(NODE_LAYER_WEIGHT, + compiler.stack_assign_if_linked(blend_in), + __float_as_int(blend), + compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(fresnel_out))); + } - if(!facing_out->links.empty()) { - compiler.add_node(NODE_LAYER_WEIGHT, - compiler.stack_assign_if_linked(blend_in), - __float_as_int(blend), - compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, - compiler.stack_assign_if_linked(normal_in), - compiler.stack_assign(facing_out))); - } + if (!facing_out->links.empty()) { + compiler.add_node(NODE_LAYER_WEIGHT, + compiler.stack_assign_if_linked(blend_in), + __float_as_int(blend), + compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(facing_out))); + } } -void LayerWeightNode::compile(OSLCompiler& compiler) +void LayerWeightNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_layer_weight"); + compiler.add(this, "node_layer_weight"); } /* Wireframe */ NODE_DEFINE(WireframeNode) { - NodeType* type = NodeType::add("wireframe", create, NodeType::SHADER); + NodeType *type = NodeType::add("wireframe", create, NodeType::SHADER); - SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false); - SOCKET_IN_FLOAT(size, "Size", 0.01f); - SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false); + SOCKET_IN_FLOAT(size, "Size", 0.01f); + SOCKET_OUT_FLOAT(fac, "Fac"); - return type; + return type; } -WireframeNode::WireframeNode() -: ShaderNode(node_type) +WireframeNode::WireframeNode() : ShaderNode(node_type) { } -void WireframeNode::compile(SVMCompiler& compiler) +void WireframeNode::compile(SVMCompiler &compiler) { - ShaderInput *size_in = input("Size"); - ShaderOutput *fac_out = output("Fac"); - NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER; - if(bump == SHADER_BUMP_DX) { - bump_offset = NODE_BUMP_OFFSET_DX; - } - else if(bump == SHADER_BUMP_DY) { - bump_offset = NODE_BUMP_OFFSET_DY; - } - compiler.add_node(NODE_WIREFRAME, - compiler.stack_assign(size_in), - compiler.stack_assign(fac_out), - compiler.encode_uchar4(use_pixel_size, - bump_offset, - 0, 0)); + ShaderInput *size_in = input("Size"); + ShaderOutput *fac_out = output("Fac"); + NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER; + if (bump == SHADER_BUMP_DX) { + bump_offset = NODE_BUMP_OFFSET_DX; + } + else if (bump == SHADER_BUMP_DY) { + bump_offset = NODE_BUMP_OFFSET_DY; + } + compiler.add_node(NODE_WIREFRAME, + compiler.stack_assign(size_in), + compiler.stack_assign(fac_out), + compiler.encode_uchar4(use_pixel_size, bump_offset, 0, 0)); } -void WireframeNode::compile(OSLCompiler& compiler) +void WireframeNode::compile(OSLCompiler &compiler) { - if(bump == SHADER_BUMP_DX) { - compiler.parameter("bump_offset", "dx"); - } - else if(bump == SHADER_BUMP_DY) { - compiler.parameter("bump_offset", "dy"); - } - else { - compiler.parameter("bump_offset", "center"); - } - compiler.parameter(this, "use_pixel_size"); - compiler.add(this, "node_wireframe"); + if (bump == SHADER_BUMP_DX) { + compiler.parameter("bump_offset", "dx"); + } + else if (bump == SHADER_BUMP_DY) { + compiler.parameter("bump_offset", "dy"); + } + else { + compiler.parameter("bump_offset", "center"); + } + compiler.parameter(this, "use_pixel_size"); + compiler.add(this, "node_wireframe"); } /* Wavelength */ NODE_DEFINE(WavelengthNode) { - NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER); + NodeType *type = NodeType::add("wavelength", create, NodeType::SHADER); - SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -WavelengthNode::WavelengthNode() -: ShaderNode(node_type) +WavelengthNode::WavelengthNode() : ShaderNode(node_type) { } -void WavelengthNode::compile(SVMCompiler& compiler) +void WavelengthNode::compile(SVMCompiler &compiler) { - ShaderInput *wavelength_in = input("Wavelength"); - ShaderOutput *color_out = output("Color"); + ShaderInput *wavelength_in = input("Wavelength"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_WAVELENGTH, - compiler.stack_assign(wavelength_in), - compiler.stack_assign(color_out)); + compiler.add_node( + NODE_WAVELENGTH, compiler.stack_assign(wavelength_in), compiler.stack_assign(color_out)); } -void WavelengthNode::compile(OSLCompiler& compiler) +void WavelengthNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_wavelength"); + compiler.add(this, "node_wavelength"); } /* Blackbody */ NODE_DEFINE(BlackbodyNode) { - NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER); + NodeType *type = NodeType::add("blackbody", create, NodeType::SHADER); - SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f); - SOCKET_OUT_COLOR(color, "Color"); + SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f); + SOCKET_OUT_COLOR(color, "Color"); - return type; + return type; } -BlackbodyNode::BlackbodyNode() -: ShaderNode(node_type) +BlackbodyNode::BlackbodyNode() : ShaderNode(node_type) { } -void BlackbodyNode::constant_fold(const ConstantFolder& folder) +void BlackbodyNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant(svm_math_blackbody_color(temperature)); - } + if (folder.all_inputs_constant()) { + folder.make_constant(svm_math_blackbody_color(temperature)); + } } -void BlackbodyNode::compile(SVMCompiler& compiler) +void BlackbodyNode::compile(SVMCompiler &compiler) { - ShaderInput *temperature_in = input("Temperature"); - ShaderOutput *color_out = output("Color"); + ShaderInput *temperature_in = input("Temperature"); + ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_BLACKBODY, - compiler.stack_assign(temperature_in), - compiler.stack_assign(color_out)); + compiler.add_node( + NODE_BLACKBODY, compiler.stack_assign(temperature_in), compiler.stack_assign(color_out)); } -void BlackbodyNode::compile(OSLCompiler& compiler) +void BlackbodyNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_blackbody"); + compiler.add(this, "node_blackbody"); } /* Output */ NODE_DEFINE(OutputNode) { - NodeType* type = NodeType::add("output", create, NodeType::SHADER); + NodeType *type = NodeType::add("output", create, NodeType::SHADER); - SOCKET_IN_CLOSURE(surface, "Surface"); - SOCKET_IN_CLOSURE(volume, "Volume"); - SOCKET_IN_VECTOR(displacement, "Displacement", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_CLOSURE(surface, "Surface"); + SOCKET_IN_CLOSURE(volume, "Volume"); + SOCKET_IN_VECTOR(displacement, "Displacement", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f)); - return type; + return type; } -OutputNode::OutputNode() -: ShaderNode(node_type) +OutputNode::OutputNode() : ShaderNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_OUTPUT; + special_type = SHADER_SPECIAL_TYPE_OUTPUT; } -void OutputNode::compile(SVMCompiler& compiler) +void OutputNode::compile(SVMCompiler &compiler) { - if(compiler.output_type() == SHADER_TYPE_DISPLACEMENT) { - ShaderInput *displacement_in = input("Displacement"); + if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) { + ShaderInput *displacement_in = input("Displacement"); - if(displacement_in->link) { - compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in)); - } - } + if (displacement_in->link) { + compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in)); + } + } } -void OutputNode::compile(OSLCompiler& compiler) +void OutputNode::compile(OSLCompiler &compiler) { - if(compiler.output_type() == SHADER_TYPE_SURFACE) - compiler.add(this, "node_output_surface"); - else if(compiler.output_type() == SHADER_TYPE_VOLUME) - compiler.add(this, "node_output_volume"); - else if(compiler.output_type() == SHADER_TYPE_DISPLACEMENT) - compiler.add(this, "node_output_displacement"); + if (compiler.output_type() == SHADER_TYPE_SURFACE) + compiler.add(this, "node_output_surface"); + else if (compiler.output_type() == SHADER_TYPE_VOLUME) + compiler.add(this, "node_output_volume"); + else if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) + compiler.add(this, "node_output_displacement"); } /* Math */ NODE_DEFINE(MathNode) { - NodeType* type = NodeType::add("math", create, NodeType::SHADER); + NodeType *type = NodeType::add("math", create, NodeType::SHADER); - static NodeEnum type_enum; - type_enum.insert("add", NODE_MATH_ADD); - type_enum.insert("subtract", NODE_MATH_SUBTRACT); - type_enum.insert("multiply", NODE_MATH_MULTIPLY); - type_enum.insert("divide", NODE_MATH_DIVIDE); - type_enum.insert("sine", NODE_MATH_SINE); - type_enum.insert("cosine", NODE_MATH_COSINE); - type_enum.insert("tangent", NODE_MATH_TANGENT); - type_enum.insert("arcsine", NODE_MATH_ARCSINE); - type_enum.insert("arccosine", NODE_MATH_ARCCOSINE); - type_enum.insert("arctangent", NODE_MATH_ARCTANGENT); - type_enum.insert("power", NODE_MATH_POWER); - type_enum.insert("logarithm", NODE_MATH_LOGARITHM); - type_enum.insert("minimum", NODE_MATH_MINIMUM); - type_enum.insert("maximum", NODE_MATH_MAXIMUM); - type_enum.insert("round", NODE_MATH_ROUND); - type_enum.insert("less_than", NODE_MATH_LESS_THAN); - type_enum.insert("greater_than", NODE_MATH_GREATER_THAN); - type_enum.insert("modulo", NODE_MATH_MODULO); - type_enum.insert("absolute", NODE_MATH_ABSOLUTE); - type_enum.insert("arctan2", NODE_MATH_ARCTAN2); - type_enum.insert("floor", NODE_MATH_FLOOR); - type_enum.insert("ceil", NODE_MATH_CEIL); - type_enum.insert("fract", NODE_MATH_FRACT); - type_enum.insert("sqrt", NODE_MATH_SQRT); - SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD); + static NodeEnum type_enum; + type_enum.insert("add", NODE_MATH_ADD); + type_enum.insert("subtract", NODE_MATH_SUBTRACT); + type_enum.insert("multiply", NODE_MATH_MULTIPLY); + type_enum.insert("divide", NODE_MATH_DIVIDE); + type_enum.insert("sine", NODE_MATH_SINE); + type_enum.insert("cosine", NODE_MATH_COSINE); + type_enum.insert("tangent", NODE_MATH_TANGENT); + type_enum.insert("arcsine", NODE_MATH_ARCSINE); + type_enum.insert("arccosine", NODE_MATH_ARCCOSINE); + type_enum.insert("arctangent", NODE_MATH_ARCTANGENT); + type_enum.insert("power", NODE_MATH_POWER); + type_enum.insert("logarithm", NODE_MATH_LOGARITHM); + type_enum.insert("minimum", NODE_MATH_MINIMUM); + type_enum.insert("maximum", NODE_MATH_MAXIMUM); + type_enum.insert("round", NODE_MATH_ROUND); + type_enum.insert("less_than", NODE_MATH_LESS_THAN); + type_enum.insert("greater_than", NODE_MATH_GREATER_THAN); + type_enum.insert("modulo", NODE_MATH_MODULO); + type_enum.insert("absolute", NODE_MATH_ABSOLUTE); + type_enum.insert("arctan2", NODE_MATH_ARCTAN2); + type_enum.insert("floor", NODE_MATH_FLOOR); + type_enum.insert("ceil", NODE_MATH_CEIL); + type_enum.insert("fract", NODE_MATH_FRACT); + type_enum.insert("sqrt", NODE_MATH_SQRT); + SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD); - SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", false); - SOCKET_IN_FLOAT(value1, "Value1", 0.0f); - SOCKET_IN_FLOAT(value2, "Value2", 0.0f); + SOCKET_IN_FLOAT(value1, "Value1", 0.0f); + SOCKET_IN_FLOAT(value2, "Value2", 0.0f); - SOCKET_OUT_FLOAT(value, "Value"); + SOCKET_OUT_FLOAT(value, "Value"); - return type; + return type; } -MathNode::MathNode() -: ShaderNode(node_type) +MathNode::MathNode() : ShaderNode(node_type) { } -void MathNode::constant_fold(const ConstantFolder& folder) +void MathNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); - } - else { - folder.fold_math(type, use_clamp); - } + if (folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); + } + else { + folder.fold_math(type, use_clamp); + } } -void MathNode::compile(SVMCompiler& compiler) +void MathNode::compile(SVMCompiler &compiler) { - ShaderInput *value1_in = input("Value1"); - ShaderInput *value2_in = input("Value2"); - ShaderOutput *value_out = output("Value"); + ShaderInput *value1_in = input("Value1"); + ShaderInput *value2_in = input("Value2"); + ShaderOutput *value_out = output("Value"); - compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in)); - compiler.add_node(NODE_MATH, compiler.stack_assign(value_out)); + compiler.add_node( + NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in)); + compiler.add_node(NODE_MATH, compiler.stack_assign(value_out)); - if(use_clamp) { - compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, compiler.stack_assign(value_out)); - compiler.add_node(NODE_MATH, compiler.stack_assign(value_out)); - } + if (use_clamp) { + compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, compiler.stack_assign(value_out)); + compiler.add_node(NODE_MATH, compiler.stack_assign(value_out)); + } } -void MathNode::compile(OSLCompiler& compiler) +void MathNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "type"); - compiler.parameter(this, "use_clamp"); - compiler.add(this, "node_math"); + compiler.parameter(this, "type"); + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_math"); } /* VectorMath */ NODE_DEFINE(VectorMathNode) { - NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER); + NodeType *type = NodeType::add("vector_math", create, NodeType::SHADER); - static NodeEnum type_enum; - type_enum.insert("add", NODE_VECTOR_MATH_ADD); - type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT); - type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE); - type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT); - type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT); - type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE); - SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD); + static NodeEnum type_enum; + type_enum.insert("add", NODE_VECTOR_MATH_ADD); + type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT); + type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE); + type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT); + type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT); + type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE); + SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD); - SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_FLOAT(value, "Value"); - SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_OUT_FLOAT(value, "Value"); + SOCKET_OUT_VECTOR(vector, "Vector"); - return type; + return type; } -VectorMathNode::VectorMathNode() -: ShaderNode(node_type) +VectorMathNode::VectorMathNode() : ShaderNode(node_type) { } -void VectorMathNode::constant_fold(const ConstantFolder& folder) +void VectorMathNode::constant_fold(const ConstantFolder &folder) { - float value; - float3 vector; + float value; + float3 vector; - if(folder.all_inputs_constant()) { - svm_vector_math(&value, - &vector, - type, - vector1, - vector2); + if (folder.all_inputs_constant()) { + svm_vector_math(&value, &vector, type, vector1, vector2); - if(folder.output == output("Value")) { - folder.make_constant(value); - } - else if(folder.output == output("Vector")) { - folder.make_constant(vector); - } - } - else { - folder.fold_vector_math(type); - } + if (folder.output == output("Value")) { + folder.make_constant(value); + } + else if (folder.output == output("Vector")) { + folder.make_constant(vector); + } + } + else { + folder.fold_vector_math(type); + } } -void VectorMathNode::compile(SVMCompiler& compiler) +void VectorMathNode::compile(SVMCompiler &compiler) { - ShaderInput *vector1_in = input("Vector1"); - ShaderInput *vector2_in = input("Vector2"); - ShaderOutput *value_out = output("Value"); - ShaderOutput *vector_out = output("Vector"); + ShaderInput *vector1_in = input("Vector1"); + ShaderInput *vector2_in = input("Vector2"); + ShaderOutput *value_out = output("Value"); + ShaderOutput *vector_out = output("Vector"); - compiler.add_node(NODE_VECTOR_MATH, - type, - compiler.stack_assign(vector1_in), - compiler.stack_assign(vector2_in)); - compiler.add_node(NODE_VECTOR_MATH, - compiler.stack_assign(value_out), - compiler.stack_assign(vector_out)); + compiler.add_node(NODE_VECTOR_MATH, + type, + compiler.stack_assign(vector1_in), + compiler.stack_assign(vector2_in)); + compiler.add_node( + NODE_VECTOR_MATH, compiler.stack_assign(value_out), compiler.stack_assign(vector_out)); } -void VectorMathNode::compile(OSLCompiler& compiler) +void VectorMathNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "type"); - compiler.add(this, "node_vector_math"); + compiler.parameter(this, "type"); + compiler.add(this, "node_vector_math"); } /* VectorTransform */ NODE_DEFINE(VectorTransformNode) { - NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER); + NodeType *type = NodeType::add("vector_transform", create, NodeType::SHADER); - static NodeEnum type_enum; - type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); - type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT); - type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL); - SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR); + static NodeEnum type_enum; + type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR); + type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT); + type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR); - static NodeEnum space_enum; - space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); - space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); - space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA); - SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); - SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); + static NodeEnum space_enum; + space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); + space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); + space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA); + SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD); + SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT); - SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_VECTOR(vector, "Vector"); - return type; + return type; } -VectorTransformNode::VectorTransformNode() -: ShaderNode(node_type) +VectorTransformNode::VectorTransformNode() : ShaderNode(node_type) { } -void VectorTransformNode::compile(SVMCompiler& compiler) +void VectorTransformNode::compile(SVMCompiler &compiler) { - ShaderInput *vector_in = input("Vector"); - ShaderOutput *vector_out = output("Vector"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *vector_out = output("Vector"); - compiler.add_node(NODE_VECTOR_TRANSFORM, - compiler.encode_uchar4(type, convert_from, convert_to), - compiler.encode_uchar4(compiler.stack_assign(vector_in), - compiler.stack_assign(vector_out))); + compiler.add_node( + NODE_VECTOR_TRANSFORM, + compiler.encode_uchar4(type, convert_from, convert_to), + compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out))); } -void VectorTransformNode::compile(OSLCompiler& compiler) +void VectorTransformNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "type"); - compiler.parameter(this, "convert_from"); - compiler.parameter(this, "convert_to"); - compiler.add(this, "node_vector_transform"); + compiler.parameter(this, "type"); + compiler.parameter(this, "convert_from"); + compiler.parameter(this, "convert_to"); + compiler.add(this, "node_vector_transform"); } /* BumpNode */ NODE_DEFINE(BumpNode) { - NodeType* type = NodeType::add("bump", create, NodeType::SHADER); + NodeType *type = NodeType::add("bump", create, NodeType::SHADER); - SOCKET_BOOLEAN(invert, "Invert", false); - SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false); + SOCKET_BOOLEAN(invert, "Invert", false); + SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false); - /* this input is used by the user, but after graph transform it is no longer - * used and moved to sampler center/x/y instead */ - SOCKET_IN_FLOAT(height, "Height", 1.0f); + /* this input is used by the user, but after graph transform it is no longer + * used and moved to sampler center/x/y instead */ + SOCKET_IN_FLOAT(height, "Height", 1.0f); - SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f); - SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f); - SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_IN_FLOAT(strength, "Strength", 1.0f); - SOCKET_IN_FLOAT(distance, "Distance", 0.1f); + SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f); + SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f); + SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_FLOAT(distance, "Distance", 0.1f); - SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_NORMAL(normal, "Normal"); - return type; + return type; } -BumpNode::BumpNode() -: ShaderNode(node_type) +BumpNode::BumpNode() : ShaderNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_BUMP; + special_type = SHADER_SPECIAL_TYPE_BUMP; } -void BumpNode::compile(SVMCompiler& compiler) +void BumpNode::compile(SVMCompiler &compiler) { - ShaderInput *center_in = input("SampleCenter"); - ShaderInput *dx_in = input("SampleX"); - ShaderInput *dy_in = input("SampleY"); - ShaderInput *normal_in = input("Normal"); - ShaderInput *strength_in = input("Strength"); - ShaderInput *distance_in = input("Distance"); - ShaderOutput *normal_out = output("Normal"); + ShaderInput *center_in = input("SampleCenter"); + ShaderInput *dx_in = input("SampleX"); + ShaderInput *dy_in = input("SampleY"); + ShaderInput *normal_in = input("Normal"); + ShaderInput *strength_in = input("Strength"); + ShaderInput *distance_in = input("Distance"); + ShaderOutput *normal_out = output("Normal"); - /* pack all parameters in the node */ - compiler.add_node(NODE_SET_BUMP, - compiler.encode_uchar4( - compiler.stack_assign_if_linked(normal_in), - compiler.stack_assign(distance_in), - invert, - use_object_space), - compiler.encode_uchar4( - compiler.stack_assign(center_in), - compiler.stack_assign(dx_in), - compiler.stack_assign(dy_in), - compiler.stack_assign(strength_in)), - compiler.stack_assign(normal_out)); + /* pack all parameters in the node */ + compiler.add_node(NODE_SET_BUMP, + compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(distance_in), + invert, + use_object_space), + compiler.encode_uchar4(compiler.stack_assign(center_in), + compiler.stack_assign(dx_in), + compiler.stack_assign(dy_in), + compiler.stack_assign(strength_in)), + compiler.stack_assign(normal_out)); } -void BumpNode::compile(OSLCompiler& compiler) +void BumpNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "invert"); - compiler.parameter(this, "use_object_space"); - compiler.add(this, "node_bump"); + compiler.parameter(this, "invert"); + compiler.parameter(this, "use_object_space"); + compiler.add(this, "node_bump"); } -void BumpNode::constant_fold(const ConstantFolder& folder) +void BumpNode::constant_fold(const ConstantFolder &folder) { - ShaderInput *height_in = input("Height"); - ShaderInput *normal_in = input("Normal"); + ShaderInput *height_in = input("Height"); + ShaderInput *normal_in = input("Normal"); - if(height_in->link == NULL) { - if(normal_in->link == NULL) { - GeometryNode *geom = new GeometryNode(); - folder.graph->add(geom); - folder.bypass(geom->output("Normal")); - } - else { - folder.bypass(normal_in->link); - } - } + if (height_in->link == NULL) { + if (normal_in->link == NULL) { + GeometryNode *geom = new GeometryNode(); + folder.graph->add(geom); + folder.bypass(geom->output("Normal")); + } + else { + folder.bypass(normal_in->link); + } + } - /* TODO(sergey): Ignore bump with zero strength. */ + /* TODO(sergey): Ignore bump with zero strength. */ } - /* Curve node */ -CurvesNode::CurvesNode(const NodeType *node_type) -: ShaderNode(node_type) +CurvesNode::CurvesNode(const NodeType *node_type) : ShaderNode(node_type) { } -void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in) +void CurvesNode::constant_fold(const ConstantFolder &folder, ShaderInput *value_in) { - ShaderInput *fac_in = input("Fac"); + ShaderInput *fac_in = input("Fac"); - /* evaluate fully constant node */ - if(folder.all_inputs_constant()) { - if(curves.size() == 0) { - return; - } + /* evaluate fully constant node */ + if (folder.all_inputs_constant()) { + if (curves.size() == 0) { + return; + } - float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x); - float3 result; + float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x); + float3 result; - result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x; - result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y; - result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z; + result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x; + result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y; + result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z; - folder.make_constant(interp(value, result, fac)); - } - /* remove no-op node */ - else if(!fac_in->link && fac == 0.0f) { - /* link is not null because otherwise all inputs are constant */ - folder.bypass(value_in->link); - } + folder.make_constant(interp(value, result, fac)); + } + /* remove no-op node */ + else if (!fac_in->link && fac == 0.0f) { + /* link is not null because otherwise all inputs are constant */ + folder.bypass(value_in->link); + } } -void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out) +void CurvesNode::compile(SVMCompiler &compiler, + int type, + ShaderInput *value_in, + ShaderOutput *value_out) { - if(curves.size() == 0) - return; + if (curves.size() == 0) + return; - ShaderInput *fac_in = input("Fac"); + ShaderInput *fac_in = input("Fac"); - compiler.add_node(type, - compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(value_in), - compiler.stack_assign(value_out)), - __float_as_int(min_x), - __float_as_int(max_x)); + compiler.add_node(type, + compiler.encode_uchar4(compiler.stack_assign(fac_in), + compiler.stack_assign(value_in), + compiler.stack_assign(value_out)), + __float_as_int(min_x), + __float_as_int(max_x)); - compiler.add_node(curves.size()); - for(int i = 0; i < curves.size(); i++) - compiler.add_node(float3_to_float4(curves[i])); + compiler.add_node(curves.size()); + for (int i = 0; i < curves.size(); i++) + compiler.add_node(float3_to_float4(curves[i])); } -void CurvesNode::compile(OSLCompiler& compiler, const char* name) +void CurvesNode::compile(OSLCompiler &compiler, const char *name) { - if(curves.size() == 0) - return; + if (curves.size() == 0) + return; - compiler.parameter_color_array("ramp", curves); - compiler.parameter(this, "min_x"); - compiler.parameter(this, "max_x"); - compiler.add(this, name); + compiler.parameter_color_array("ramp", curves); + compiler.parameter(this, "min_x"); + compiler.parameter(this, "max_x"); + compiler.add(this, name); } -void CurvesNode::compile(SVMCompiler& /*compiler*/) +void CurvesNode::compile(SVMCompiler & /*compiler*/) { - assert(0); + assert(0); } -void CurvesNode::compile(OSLCompiler& /*compiler*/) +void CurvesNode::compile(OSLCompiler & /*compiler*/) { - assert(0); + assert(0); } /* RGBCurvesNode */ NODE_DEFINE(RGBCurvesNode) { - NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER); + NodeType *type = NodeType::add("rgb_curves", create, NodeType::SHADER); - SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>()); - SOCKET_FLOAT(min_x, "Min X", 0.0f); - SOCKET_FLOAT(max_x, "Max X", 1.0f); + SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); - SOCKET_IN_FLOAT(fac, "Fac", 0.0f); - SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_COLOR(value, "Color"); + SOCKET_OUT_COLOR(value, "Color"); - return type; + return type; } -RGBCurvesNode::RGBCurvesNode() -: CurvesNode(node_type) +RGBCurvesNode::RGBCurvesNode() : CurvesNode(node_type) { } -void RGBCurvesNode::constant_fold(const ConstantFolder& folder) +void RGBCurvesNode::constant_fold(const ConstantFolder &folder) { - CurvesNode::constant_fold(folder, input("Color")); + CurvesNode::constant_fold(folder, input("Color")); } -void RGBCurvesNode::compile(SVMCompiler& compiler) +void RGBCurvesNode::compile(SVMCompiler &compiler) { - CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); + CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); } -void RGBCurvesNode::compile(OSLCompiler& compiler) +void RGBCurvesNode::compile(OSLCompiler &compiler) { - CurvesNode::compile(compiler, "node_rgb_curves"); + CurvesNode::compile(compiler, "node_rgb_curves"); } /* VectorCurvesNode */ NODE_DEFINE(VectorCurvesNode) { - NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER); + NodeType *type = NodeType::add("vector_curves", create, NodeType::SHADER); - SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>()); - SOCKET_FLOAT(min_x, "Min X", 0.0f); - SOCKET_FLOAT(max_x, "Max X", 1.0f); + SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); - SOCKET_IN_FLOAT(fac, "Fac", 0.0f); - SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_VECTOR(value, "Vector"); + SOCKET_OUT_VECTOR(value, "Vector"); - return type; + return type; } -VectorCurvesNode::VectorCurvesNode() -: CurvesNode(node_type) +VectorCurvesNode::VectorCurvesNode() : CurvesNode(node_type) { } -void VectorCurvesNode::constant_fold(const ConstantFolder& folder) +void VectorCurvesNode::constant_fold(const ConstantFolder &folder) { - CurvesNode::constant_fold(folder, input("Vector")); + CurvesNode::constant_fold(folder, input("Vector")); } -void VectorCurvesNode::compile(SVMCompiler& compiler) +void VectorCurvesNode::compile(SVMCompiler &compiler) { - CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); + CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); } -void VectorCurvesNode::compile(OSLCompiler& compiler) +void VectorCurvesNode::compile(OSLCompiler &compiler) { - CurvesNode::compile(compiler, "node_vector_curves"); + CurvesNode::compile(compiler, "node_vector_curves"); } /* RGBRampNode */ NODE_DEFINE(RGBRampNode) { - NodeType* type = NodeType::add("rgb_ramp", create, NodeType::SHADER); + NodeType *type = NodeType::add("rgb_ramp", create, NodeType::SHADER); - SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>()); - SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>()); - SOCKET_BOOLEAN(interpolate, "Interpolate", true); + SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>()); + SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>()); + SOCKET_BOOLEAN(interpolate, "Interpolate", true); - SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); - SOCKET_OUT_COLOR(color, "Color"); - SOCKET_OUT_FLOAT(alpha, "Alpha"); + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(alpha, "Alpha"); - return type; + return type; } -RGBRampNode::RGBRampNode() -: ShaderNode(node_type) +RGBRampNode::RGBRampNode() : ShaderNode(node_type) { } -void RGBRampNode::constant_fold(const ConstantFolder& folder) +void RGBRampNode::constant_fold(const ConstantFolder &folder) { - if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) - return; + if (ramp.size() == 0 || ramp.size() != ramp_alpha.size()) + return; - if(folder.all_inputs_constant()) { - float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1); + if (folder.all_inputs_constant()) { + float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1); - /* clamp int as well in case of NaN */ - int i = clamp((int)f, 0, ramp.size()-1); - float t = f - (float)i; + /* clamp int as well in case of NaN */ + int i = clamp((int)f, 0, ramp.size() - 1); + float t = f - (float)i; - bool use_lerp = interpolate && t > 0.0f; + bool use_lerp = interpolate && t > 0.0f; - if(folder.output == output("Color")) { - float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size()); - folder.make_constant(color); - } - else if(folder.output == output("Alpha")) { - float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size()); - folder.make_constant(alpha); - } - } + if (folder.output == output("Color")) { + float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size()); + folder.make_constant(color); + } + else if (folder.output == output("Alpha")) { + float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size()); + folder.make_constant(alpha); + } + } } -void RGBRampNode::compile(SVMCompiler& compiler) +void RGBRampNode::compile(SVMCompiler &compiler) { - if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) - return; + if (ramp.size() == 0 || ramp.size() != ramp_alpha.size()) + return; - ShaderInput *fac_in = input("Fac"); - ShaderOutput *color_out = output("Color"); - ShaderOutput *alpha_out = output("Alpha"); + ShaderInput *fac_in = input("Fac"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *alpha_out = output("Alpha"); - compiler.add_node(NODE_RGB_RAMP, - compiler.encode_uchar4( - compiler.stack_assign(fac_in), - compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(alpha_out)), - interpolate); + compiler.add_node(NODE_RGB_RAMP, + compiler.encode_uchar4(compiler.stack_assign(fac_in), + compiler.stack_assign_if_linked(color_out), + compiler.stack_assign_if_linked(alpha_out)), + interpolate); - compiler.add_node(ramp.size()); - for(int i = 0; i < ramp.size(); i++) - compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i])); + compiler.add_node(ramp.size()); + for (int i = 0; i < ramp.size(); i++) + compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i])); } -void RGBRampNode::compile(OSLCompiler& compiler) +void RGBRampNode::compile(OSLCompiler &compiler) { - if(ramp.size() == 0 || ramp.size() != ramp_alpha.size()) - return; + if (ramp.size() == 0 || ramp.size() != ramp_alpha.size()) + return; - compiler.parameter_color_array("ramp_color", ramp); - compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size()); - compiler.parameter(this, "interpolate"); + compiler.parameter_color_array("ramp_color", ramp); + compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size()); + compiler.parameter(this, "interpolate"); - compiler.add(this, "node_rgb_ramp"); + compiler.add(this, "node_rgb_ramp"); } /* Set Normal Node */ NODE_DEFINE(SetNormalNode) { - NodeType* type = NodeType::add("set_normal", create, NodeType::SHADER); + NodeType *type = NodeType::add("set_normal", create, NodeType::SHADER); - SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_NORMAL(normal, "Normal"); - return type; + return type; } -SetNormalNode::SetNormalNode() -: ShaderNode(node_type) +SetNormalNode::SetNormalNode() : ShaderNode(node_type) { } -void SetNormalNode::compile(SVMCompiler& compiler) +void SetNormalNode::compile(SVMCompiler &compiler) { - ShaderInput *direction_in = input("Direction"); - ShaderOutput *normal_out = output("Normal"); + ShaderInput *direction_in = input("Direction"); + ShaderOutput *normal_out = output("Normal"); - compiler.add_node(NODE_CLOSURE_SET_NORMAL, - compiler.stack_assign(direction_in), - compiler.stack_assign(normal_out)); + compiler.add_node(NODE_CLOSURE_SET_NORMAL, + compiler.stack_assign(direction_in), + compiler.stack_assign(normal_out)); } -void SetNormalNode::compile(OSLCompiler& compiler) +void SetNormalNode::compile(OSLCompiler &compiler) { - compiler.add(this, "node_set_normal"); + compiler.add(this, "node_set_normal"); } /* OSLNode */ -OSLNode::OSLNode() -: ShaderNode(new NodeType(NodeType::SHADER)) +OSLNode::OSLNode() : ShaderNode(new NodeType(NodeType::SHADER)) { - special_type = SHADER_SPECIAL_TYPE_SCRIPT; + special_type = SHADER_SPECIAL_TYPE_SCRIPT; } OSLNode::~OSLNode() { - delete type; + delete type; } ShaderNode *OSLNode::clone() const { - return OSLNode::create(this->inputs.size(), this); + return OSLNode::create(this->inputs.size(), this); } -OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from) +OSLNode *OSLNode::create(size_t num_inputs, const OSLNode *from) { - /* allocate space for the node itself and parameters, aligned to 16 bytes - * assuming that's the most parameter types need */ - size_t node_size = align_up(sizeof(OSLNode), 16); - size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; + /* allocate space for the node itself and parameters, aligned to 16 bytes + * assuming that's the most parameter types need */ + size_t node_size = align_up(sizeof(OSLNode), 16); + size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; - char *node_memory = (char*) operator new(node_size + inputs_size); - memset(node_memory, 0, node_size + inputs_size); + char *node_memory = (char *)operator new(node_size + inputs_size); + memset(node_memory, 0, node_size + inputs_size); - if(!from) { - return new(node_memory) OSLNode(); - } - else { - /* copy input default values and node type for cloning */ - memcpy(node_memory + node_size, (char*)from + node_size, inputs_size); + if (!from) { + return new (node_memory) OSLNode(); + } + else { + /* copy input default values and node type for cloning */ + memcpy(node_memory + node_size, (char *)from + node_size, inputs_size); - OSLNode *node = new(node_memory) OSLNode(*from); - node->type = new NodeType(*(from->type)); - return node; - } + OSLNode *node = new (node_memory) OSLNode(*from); + node->type = new NodeType(*(from->type)); + return node; + } } -char* OSLNode::input_default_value() +char *OSLNode::input_default_value() { - /* pointer to default value storage, which is the same as our actual value */ - size_t num_inputs = type->inputs.size(); - size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; - return (char*)this + align_up(sizeof(OSLNode), 16) + inputs_size; + /* pointer to default value storage, which is the same as our actual value */ + size_t num_inputs = type->inputs.size(); + size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs; + return (char *)this + align_up(sizeof(OSLNode), 16) + inputs_size; } void OSLNode::add_input(ustring name, SocketType::Type socket_type) { - char *memory = input_default_value(); - size_t offset = memory - (char*)this; - const_cast<NodeType*>(type)->register_input(name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE); + char *memory = input_default_value(); + size_t offset = memory - (char *)this; + const_cast<NodeType *>(type)->register_input( + name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE); } void OSLNode::add_output(ustring name, SocketType::Type socket_type) { - const_cast<NodeType*>(type)->register_output(name, name, socket_type); + const_cast<NodeType *>(type)->register_output(name, name, socket_type); } -void OSLNode::compile(SVMCompiler&) +void OSLNode::compile(SVMCompiler &) { - /* doesn't work for SVM, obviously ... */ + /* doesn't work for SVM, obviously ... */ } -void OSLNode::compile(OSLCompiler& compiler) +void OSLNode::compile(OSLCompiler &compiler) { - if(!filepath.empty()) - compiler.add(this, filepath.c_str(), true); - else - compiler.add(this, bytecode_hash.c_str(), false); + if (!filepath.empty()) + compiler.add(this, filepath.c_str(), true); + else + compiler.add(this, bytecode_hash.c_str(), false); } /* Normal Map */ NODE_DEFINE(NormalMapNode) { - NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER); + NodeType *type = NodeType::add("normal_map", create, NodeType::SHADER); - static NodeEnum space_enum; - space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT); - space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); - space_enum.insert("world", NODE_NORMAL_MAP_WORLD); - space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT); - space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD); - SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT); + static NodeEnum space_enum; + space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT); + space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); + space_enum.insert("world", NODE_NORMAL_MAP_WORLD); + space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT); + space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD); + SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT); - SOCKET_STRING(attribute, "Attribute", ustring()); + SOCKET_STRING(attribute, "Attribute", ustring()); - SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - SOCKET_IN_FLOAT(strength, "Strength", 1.0f); - SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f)); + SOCKET_IN_NORMAL(normal_osl, + "NormalIn", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f)); - SOCKET_OUT_NORMAL(normal, "Normal"); + SOCKET_OUT_NORMAL(normal, "Normal"); - return type; + return type; } -NormalMapNode::NormalMapNode() -: ShaderNode(node_type) +NormalMapNode::NormalMapNode() : ShaderNode(node_type) { } void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { - if(attribute.empty()) { - attributes->add(ATTR_STD_UV_TANGENT); - attributes->add(ATTR_STD_UV_TANGENT_SIGN); - } - else { - attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str())); - attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); - } - - attributes->add(ATTR_STD_VERTEX_NORMAL); - } - - ShaderNode::attributes(shader, attributes); -} - -void NormalMapNode::compile(SVMCompiler& compiler) -{ - ShaderInput *color_in = input("Color"); - ShaderInput *strength_in = input("Strength"); - ShaderOutput *normal_out = output("Normal"); - int attr = 0, attr_sign = 0; - - if(space == NODE_NORMAL_MAP_TANGENT) { - if(attribute.empty()) { - attr = compiler.attribute(ATTR_STD_UV_TANGENT); - attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN); - } - else { - attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str())); - attr_sign = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); - } - } - - compiler.add_node(NODE_NORMAL_MAP, - compiler.encode_uchar4( - compiler.stack_assign(color_in), - compiler.stack_assign(strength_in), - compiler.stack_assign(normal_out), - space), - attr, attr_sign); -} - -void NormalMapNode::compile(OSLCompiler& compiler) -{ - if(space == NODE_NORMAL_MAP_TANGENT) { - if(attribute.empty()) { - compiler.parameter("attr_name", ustring("geom:tangent")); - compiler.parameter("attr_sign_name", ustring("geom:tangent_sign")); - } - else { - compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); - compiler.parameter("attr_sign_name", ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); - } - } - - compiler.parameter(this, "space"); - compiler.add(this, "node_normal_map"); + if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { + if (attribute.empty()) { + attributes->add(ATTR_STD_UV_TANGENT); + attributes->add(ATTR_STD_UV_TANGENT_SIGN); + } + else { + attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str())); + attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); + } + + attributes->add(ATTR_STD_VERTEX_NORMAL); + } + + ShaderNode::attributes(shader, attributes); +} + +void NormalMapNode::compile(SVMCompiler &compiler) +{ + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); + ShaderOutput *normal_out = output("Normal"); + int attr = 0, attr_sign = 0; + + if (space == NODE_NORMAL_MAP_TANGENT) { + if (attribute.empty()) { + attr = compiler.attribute(ATTR_STD_UV_TANGENT); + attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN); + } + else { + attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str())); + attr_sign = compiler.attribute( + ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); + } + } + + compiler.add_node(NODE_NORMAL_MAP, + compiler.encode_uchar4(compiler.stack_assign(color_in), + compiler.stack_assign(strength_in), + compiler.stack_assign(normal_out), + space), + attr, + attr_sign); +} + +void NormalMapNode::compile(OSLCompiler &compiler) +{ + if (space == NODE_NORMAL_MAP_TANGENT) { + if (attribute.empty()) { + compiler.parameter("attr_name", ustring("geom:tangent")); + compiler.parameter("attr_sign_name", ustring("geom:tangent_sign")); + } + else { + compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); + compiler.parameter("attr_sign_name", + ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); + } + } + + compiler.parameter(this, "space"); + compiler.add(this, "node_normal_map"); } /* Tangent */ NODE_DEFINE(TangentNode) { - NodeType* type = NodeType::add("tangent", create, NodeType::SHADER); + NodeType *type = NodeType::add("tangent", create, NodeType::SHADER); - static NodeEnum direction_type_enum; - direction_type_enum.insert("radial", NODE_TANGENT_RADIAL); - direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP); - SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL); + static NodeEnum direction_type_enum; + direction_type_enum.insert("radial", NODE_TANGENT_RADIAL); + direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP); + SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL); - static NodeEnum axis_enum; - axis_enum.insert("x", NODE_TANGENT_AXIS_X); - axis_enum.insert("y", NODE_TANGENT_AXIS_Y); - axis_enum.insert("z", NODE_TANGENT_AXIS_Z); - SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X); + static NodeEnum axis_enum; + axis_enum.insert("x", NODE_TANGENT_AXIS_X); + axis_enum.insert("y", NODE_TANGENT_AXIS_Y); + axis_enum.insert("z", NODE_TANGENT_AXIS_Z); + SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X); - SOCKET_STRING(attribute, "Attribute", ustring()); + SOCKET_STRING(attribute, "Attribute", ustring()); - SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); - SOCKET_OUT_NORMAL(tangent, "Tangent"); + SOCKET_IN_NORMAL(normal_osl, + "NormalIn", + make_float3(0.0f, 0.0f, 0.0f), + SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_OUT_NORMAL(tangent, "Tangent"); - return type; + return type; } -TangentNode::TangentNode() -: ShaderNode(node_type) +TangentNode::TangentNode() : ShaderNode(node_type) { } void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - if(direction_type == NODE_TANGENT_UVMAP) { - if(attribute.empty()) - attributes->add(ATTR_STD_UV_TANGENT); - else - attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str())); - } - else - attributes->add(ATTR_STD_GENERATED); - } + if (shader->has_surface) { + if (direction_type == NODE_TANGENT_UVMAP) { + if (attribute.empty()) + attributes->add(ATTR_STD_UV_TANGENT); + else + attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str())); + } + else + attributes->add(ATTR_STD_GENERATED); + } - ShaderNode::attributes(shader, attributes); + ShaderNode::attributes(shader, attributes); } -void TangentNode::compile(SVMCompiler& compiler) +void TangentNode::compile(SVMCompiler &compiler) { - ShaderOutput *tangent_out = output("Tangent"); - int attr; + ShaderOutput *tangent_out = output("Tangent"); + int attr; - if(direction_type == NODE_TANGENT_UVMAP) { - if(attribute.empty()) - attr = compiler.attribute(ATTR_STD_UV_TANGENT); - else - attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str())); - } - else - attr = compiler.attribute(ATTR_STD_GENERATED); + if (direction_type == NODE_TANGENT_UVMAP) { + if (attribute.empty()) + attr = compiler.attribute(ATTR_STD_UV_TANGENT); + else + attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str())); + } + else + attr = compiler.attribute(ATTR_STD_GENERATED); - compiler.add_node(NODE_TANGENT, - compiler.encode_uchar4( - compiler.stack_assign(tangent_out), - direction_type, - axis), attr); + compiler.add_node( + NODE_TANGENT, + compiler.encode_uchar4(compiler.stack_assign(tangent_out), direction_type, axis), + attr); } -void TangentNode::compile(OSLCompiler& compiler) +void TangentNode::compile(OSLCompiler &compiler) { - if(direction_type == NODE_TANGENT_UVMAP) { - if(attribute.empty()) - compiler.parameter("attr_name", ustring("geom:tangent")); - else - compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); - } + if (direction_type == NODE_TANGENT_UVMAP) { + if (attribute.empty()) + compiler.parameter("attr_name", ustring("geom:tangent")); + else + compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); + } - compiler.parameter(this, "direction_type"); - compiler.parameter(this, "axis"); - compiler.add(this, "node_tangent"); + compiler.parameter(this, "direction_type"); + compiler.parameter(this, "axis"); + compiler.add(this, "node_tangent"); } /* Bevel */ NODE_DEFINE(BevelNode) { - NodeType* type = NodeType::add("bevel", create, NodeType::SHADER); + NodeType *type = NodeType::add("bevel", create, NodeType::SHADER); - SOCKET_INT(samples, "Samples", 4); + SOCKET_INT(samples, "Samples", 4); - SOCKET_IN_FLOAT(radius, "Radius", 0.05f); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(radius, "Radius", 0.05f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_OUT_NORMAL(bevel, "Normal"); + SOCKET_OUT_NORMAL(bevel, "Normal"); - return type; + return type; } -BevelNode::BevelNode() -: ShaderNode(node_type) +BevelNode::BevelNode() : ShaderNode(node_type) { } -void BevelNode::compile(SVMCompiler& compiler) +void BevelNode::compile(SVMCompiler &compiler) { - ShaderInput *radius_in = input("Radius"); - ShaderInput *normal_in = input("Normal"); - ShaderOutput *normal_out = output("Normal"); + ShaderInput *radius_in = input("Radius"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *normal_out = output("Normal"); - compiler.add_node(NODE_BEVEL, - compiler.encode_uchar4(samples, - compiler.stack_assign(radius_in), - compiler.stack_assign_if_linked(normal_in), - compiler.stack_assign(normal_out))); + compiler.add_node(NODE_BEVEL, + compiler.encode_uchar4(samples, + compiler.stack_assign(radius_in), + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(normal_out))); } -void BevelNode::compile(OSLCompiler& compiler) +void BevelNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "samples"); - compiler.add(this, "node_bevel"); + compiler.parameter(this, "samples"); + compiler.add(this, "node_bevel"); } /* Displacement */ NODE_DEFINE(DisplacementNode) { - NodeType* type = NodeType::add("displacement", create, NodeType::SHADER); + NodeType *type = NodeType::add("displacement", create, NodeType::SHADER); - static NodeEnum space_enum; - space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); - space_enum.insert("world", NODE_NORMAL_MAP_WORLD); + static NodeEnum space_enum; + space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); + space_enum.insert("world", NODE_NORMAL_MAP_WORLD); - SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_OBJECT); + SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_OBJECT); - SOCKET_IN_FLOAT(height, "Height", 0.0f); - SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.5f); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(height, "Height", 0.0f); + SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.5f); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_OUT_VECTOR(displacement, "Displacement"); + SOCKET_OUT_VECTOR(displacement, "Displacement"); - return type; + return type; } -DisplacementNode::DisplacementNode() -: ShaderNode(node_type) +DisplacementNode::DisplacementNode() : ShaderNode(node_type) { } -void DisplacementNode::constant_fold(const ConstantFolder& folder) +void DisplacementNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - if((height - midlevel == 0.0f) || (scale == 0.0f)) { - folder.make_zero(); - } - } + if (folder.all_inputs_constant()) { + if ((height - midlevel == 0.0f) || (scale == 0.0f)) { + folder.make_zero(); + } + } } -void DisplacementNode::compile(SVMCompiler& compiler) +void DisplacementNode::compile(SVMCompiler &compiler) { - ShaderInput *height_in = input("Height"); - ShaderInput *midlevel_in = input("Midlevel"); - ShaderInput *scale_in = input("Scale"); - ShaderInput *normal_in = input("Normal"); - ShaderOutput *displacement_out = output("Displacement"); + ShaderInput *height_in = input("Height"); + ShaderInput *midlevel_in = input("Midlevel"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *displacement_out = output("Displacement"); - compiler.add_node(NODE_DISPLACEMENT, - compiler.encode_uchar4(compiler.stack_assign(height_in), - compiler.stack_assign(midlevel_in), - compiler.stack_assign(scale_in), - compiler.stack_assign_if_linked(normal_in)), - compiler.stack_assign(displacement_out), - space); + compiler.add_node(NODE_DISPLACEMENT, + compiler.encode_uchar4(compiler.stack_assign(height_in), + compiler.stack_assign(midlevel_in), + compiler.stack_assign(scale_in), + compiler.stack_assign_if_linked(normal_in)), + compiler.stack_assign(displacement_out), + space); } -void DisplacementNode::compile(OSLCompiler& compiler) +void DisplacementNode::compile(OSLCompiler &compiler) { - compiler.parameter(this, "space"); - compiler.add(this, "node_displacement"); + compiler.parameter(this, "space"); + compiler.add(this, "node_displacement"); } /* Vector Displacement */ NODE_DEFINE(VectorDisplacementNode) { - NodeType* type = NodeType::add("vector_displacement", create, NodeType::SHADER); + NodeType *type = NodeType::add("vector_displacement", create, NodeType::SHADER); - static NodeEnum space_enum; - space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT); - space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); - space_enum.insert("world", NODE_NORMAL_MAP_WORLD); + static NodeEnum space_enum; + space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT); + space_enum.insert("object", NODE_NORMAL_MAP_OBJECT); + space_enum.insert("world", NODE_NORMAL_MAP_WORLD); - SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT); - SOCKET_STRING(attribute, "Attribute", ustring()); + SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT); + SOCKET_STRING(attribute, "Attribute", ustring()); - SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f); - SOCKET_IN_FLOAT(scale, "Scale", 1.0f); + SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f); + SOCKET_IN_FLOAT(scale, "Scale", 1.0f); - SOCKET_OUT_VECTOR(displacement, "Displacement"); + SOCKET_OUT_VECTOR(displacement, "Displacement"); - return type; + return type; } -VectorDisplacementNode::VectorDisplacementNode() -: ShaderNode(node_type) +VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(node_type) { } -void VectorDisplacementNode::constant_fold(const ConstantFolder& folder) +void VectorDisplacementNode::constant_fold(const ConstantFolder &folder) { - if(folder.all_inputs_constant()) { - if((vector == make_float3(0.0f, 0.0f, 0.0f) && midlevel == 0.0f) || - (scale == 0.0f)) { - folder.make_zero(); - } - } + if (folder.all_inputs_constant()) { + if ((vector == make_float3(0.0f, 0.0f, 0.0f) && midlevel == 0.0f) || (scale == 0.0f)) { + folder.make_zero(); + } + } } void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { - if(attribute.empty()) { - attributes->add(ATTR_STD_UV_TANGENT); - attributes->add(ATTR_STD_UV_TANGENT_SIGN); - } - else { - attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str())); - attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); - } - - attributes->add(ATTR_STD_VERTEX_NORMAL); - } - - ShaderNode::attributes(shader, attributes); -} - -void VectorDisplacementNode::compile(SVMCompiler& compiler) -{ - ShaderInput *vector_in = input("Vector"); - ShaderInput *midlevel_in = input("Midlevel"); - ShaderInput *scale_in = input("Scale"); - ShaderOutput *displacement_out = output("Displacement"); - int attr = 0, attr_sign = 0; - - if(space == NODE_NORMAL_MAP_TANGENT) { - if(attribute.empty()) { - attr = compiler.attribute(ATTR_STD_UV_TANGENT); - attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN); - } - else { - attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str())); - attr_sign = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); - } - } - - compiler.add_node(NODE_VECTOR_DISPLACEMENT, - compiler.encode_uchar4(compiler.stack_assign(vector_in), - compiler.stack_assign(midlevel_in), - compiler.stack_assign(scale_in), - compiler.stack_assign(displacement_out)), - attr, attr_sign); - - compiler.add_node(space); -} - -void VectorDisplacementNode::compile(OSLCompiler& compiler) -{ - if(space == NODE_NORMAL_MAP_TANGENT) { - if(attribute.empty()) { - compiler.parameter("attr_name", ustring("geom:tangent")); - compiler.parameter("attr_sign_name", ustring("geom:tangent_sign")); - } - else { - compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); - compiler.parameter("attr_sign_name", ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); - } - } - - compiler.parameter(this, "space"); - compiler.add(this, "node_vector_displacement"); + if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) { + if (attribute.empty()) { + attributes->add(ATTR_STD_UV_TANGENT); + attributes->add(ATTR_STD_UV_TANGENT_SIGN); + } + else { + attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str())); + attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); + } + + attributes->add(ATTR_STD_VERTEX_NORMAL); + } + + ShaderNode::attributes(shader, attributes); +} + +void VectorDisplacementNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *midlevel_in = input("Midlevel"); + ShaderInput *scale_in = input("Scale"); + ShaderOutput *displacement_out = output("Displacement"); + int attr = 0, attr_sign = 0; + + if (space == NODE_NORMAL_MAP_TANGENT) { + if (attribute.empty()) { + attr = compiler.attribute(ATTR_STD_UV_TANGENT); + attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN); + } + else { + attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str())); + attr_sign = compiler.attribute( + ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); + } + } + + compiler.add_node(NODE_VECTOR_DISPLACEMENT, + compiler.encode_uchar4(compiler.stack_assign(vector_in), + compiler.stack_assign(midlevel_in), + compiler.stack_assign(scale_in), + compiler.stack_assign(displacement_out)), + attr, + attr_sign); + + compiler.add_node(space); +} + +void VectorDisplacementNode::compile(OSLCompiler &compiler) +{ + if (space == NODE_NORMAL_MAP_TANGENT) { + if (attribute.empty()) { + compiler.parameter("attr_name", ustring("geom:tangent")); + compiler.parameter("attr_sign_name", ustring("geom:tangent_sign")); + } + else { + compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str())); + compiler.parameter("attr_sign_name", + ustring((string(attribute.c_str()) + ".tangent_sign").c_str())); + } + } + + compiler.parameter(this, "space"); + compiler.add(this, "node_vector_displacement"); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 5571c525e9a..7796711115e 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -33,1137 +33,1459 @@ class Shader; /* Texture Mapping */ class TextureMapping { -public: - TextureMapping(); - Transform compute_transform(); - bool skip(); - void compile(SVMCompiler& compiler, int offset_in, int offset_out); - int compile(SVMCompiler& compiler, ShaderInput *vector_in); - void compile(OSLCompiler &compiler); + public: + TextureMapping(); + Transform compute_transform(); + bool skip(); + void compile(SVMCompiler &compiler, int offset_in, int offset_out); + int compile(SVMCompiler &compiler, ShaderInput *vector_in); + void compile(OSLCompiler &compiler); - int compile_begin(SVMCompiler& compiler, ShaderInput *vector_in); - void compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset); + int compile_begin(SVMCompiler &compiler, ShaderInput *vector_in); + void compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset); - float3 translation; - float3 rotation; - float3 scale; + float3 translation; + float3 rotation; + float3 scale; - float3 min, max; - bool use_minmax; + float3 min, max; + bool use_minmax; - enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 }; - Type type; + enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 }; + Type type; - enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 }; - Mapping x_mapping, y_mapping, z_mapping; + enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 }; + Mapping x_mapping, y_mapping, z_mapping; - enum Projection { FLAT, CUBE, TUBE, SPHERE }; - Projection projection; + enum Projection { FLAT, CUBE, TUBE, SPHERE }; + Projection projection; }; /* Nodes */ class TextureNode : public ShaderNode { -public: - explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type) {} - TextureMapping tex_mapping; + public: + explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type) + { + } + TextureMapping tex_mapping; }; /* Any node which uses image manager's slot should be a subclass of this one. */ class ImageSlotTextureNode : public TextureNode { -public: - explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) { - special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT; - } - int slot; + public: + explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) + { + special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT; + } + int slot; }; class ImageTextureNode : public ImageSlotTextureNode { -public: - SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode) - ~ImageTextureNode(); - ShaderNode *clone() const; - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - - ImageManager *image_manager; - int is_float; - bool is_linear; - bool use_alpha; - ustring filename; - void *builtin_data; - NodeImageColorSpace color_space; - NodeImageProjection projection; - InterpolationType interpolation; - ExtensionType extension; - float projection_blend; - bool animated; - float3 vector; - - virtual bool equals(const ShaderNode& other) - { - const ImageTextureNode& image_node = (const ImageTextureNode&)other; - return ImageSlotTextureNode::equals(other) && - builtin_data == image_node.builtin_data && - animated == image_node.animated; - } + public: + SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode) + ~ImageTextureNode(); + ShaderNode *clone() const; + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + + ImageManager *image_manager; + int is_float; + bool is_linear; + bool use_alpha; + ustring filename; + void *builtin_data; + NodeImageColorSpace color_space; + NodeImageProjection projection; + InterpolationType interpolation; + ExtensionType extension; + float projection_blend; + bool animated; + float3 vector; + + virtual bool equals(const ShaderNode &other) + { + const ImageTextureNode &image_node = (const ImageTextureNode &)other; + return ImageSlotTextureNode::equals(other) && builtin_data == image_node.builtin_data && + animated == image_node.animated; + } }; class EnvironmentTextureNode : public ImageSlotTextureNode { -public: - SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode) - ~EnvironmentTextureNode(); - ShaderNode *clone() const; - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_2; } - - ImageManager *image_manager; - int is_float; - bool is_linear; - bool use_alpha; - ustring filename; - void *builtin_data; - NodeImageColorSpace color_space; - NodeEnvironmentProjection projection; - InterpolationType interpolation; - bool animated; - float3 vector; - - virtual bool equals(const ShaderNode& other) - { - const EnvironmentTextureNode& env_node = (const EnvironmentTextureNode&)other; - return ImageSlotTextureNode::equals(other) && - builtin_data == env_node.builtin_data && - animated == env_node.animated; - } + public: + SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode) + ~EnvironmentTextureNode(); + ShaderNode *clone() const; + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } + + ImageManager *image_manager; + int is_float; + bool is_linear; + bool use_alpha; + ustring filename; + void *builtin_data; + NodeImageColorSpace color_space; + NodeEnvironmentProjection projection; + InterpolationType interpolation; + bool animated; + float3 vector; + + virtual bool equals(const ShaderNode &other) + { + const EnvironmentTextureNode &env_node = (const EnvironmentTextureNode &)other; + return ImageSlotTextureNode::equals(other) && builtin_data == env_node.builtin_data && + animated == env_node.animated; + } }; class SkyTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(SkyTextureNode) + public: + SHADER_NODE_CLASS(SkyTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - NodeSkyType type; - float3 sun_direction; - float turbidity; - float ground_albedo; - float3 vector; + NodeSkyType type; + float3 sun_direction; + float turbidity; + float ground_albedo; + float3 vector; }; class OutputNode : public ShaderNode { -public: - SHADER_NODE_CLASS(OutputNode) + public: + SHADER_NODE_CLASS(OutputNode) - void *surface; - void *volume; - float3 displacement; - float3 normal; + void *surface; + void *volume; + float3 displacement; + float3 normal; - /* Don't allow output node de-duplication. */ - virtual bool equals(const ShaderNode& /*other*/) { return false; } + /* Don't allow output node de-duplication. */ + virtual bool equals(const ShaderNode & /*other*/) + { + return false; + } }; class GradientTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(GradientTextureNode) + public: + SHADER_NODE_CLASS(GradientTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - NodeGradientType type; - float3 vector; + NodeGradientType type; + float3 vector; }; class NoiseTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(NoiseTextureNode) + public: + SHADER_NODE_CLASS(NoiseTextureNode) - float scale, detail, distortion; - float3 vector; + float scale, detail, distortion; + float3 vector; }; class VoronoiTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(VoronoiTextureNode) + public: + SHADER_NODE_CLASS(VoronoiTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - NodeVoronoiColoring coloring; - NodeVoronoiDistanceMetric metric; - NodeVoronoiFeature feature; - float scale, exponent; - float3 vector; + NodeVoronoiColoring coloring; + NodeVoronoiDistanceMetric metric; + NodeVoronoiFeature feature; + float scale, exponent; + float3 vector; }; class MusgraveTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(MusgraveTextureNode) + public: + SHADER_NODE_CLASS(MusgraveTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - NodeMusgraveType type; - float scale, detail, dimension, lacunarity, offset, gain; - float3 vector; + NodeMusgraveType type; + float scale, detail, dimension, lacunarity, offset, gain; + float3 vector; }; class WaveTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(WaveTextureNode) + public: + SHADER_NODE_CLASS(WaveTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - NodeWaveType type; - NodeWaveProfile profile; + NodeWaveType type; + NodeWaveProfile profile; - float scale, distortion, detail, detail_scale; - float3 vector; + float scale, distortion, detail, detail_scale; + float3 vector; }; class MagicTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(MagicTextureNode) + public: + SHADER_NODE_CLASS(MagicTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - int depth; - float3 vector; - float scale, distortion; + int depth; + float3 vector; + float scale, distortion; }; class CheckerTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(CheckerTextureNode) + public: + SHADER_NODE_CLASS(CheckerTextureNode) - float3 vector, color1, color2; - float scale; + float3 vector, color1, color2; + float scale; - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } }; class BrickTextureNode : public TextureNode { -public: - SHADER_NODE_CLASS(BrickTextureNode) + public: + SHADER_NODE_CLASS(BrickTextureNode) - float offset, squash; - int offset_frequency, squash_frequency; + float offset, squash; + int offset_frequency, squash_frequency; - float3 color1, color2, mortar; - float scale, mortar_size, mortar_smooth, bias, brick_width, row_height; - float3 vector; + float3 color1, color2, mortar; + float scale, mortar_size, mortar_smooth, bias, brick_width, row_height; + float3 vector; - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } }; class PointDensityTextureNode : public ShaderNode { -public: - SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode) - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - - ~PointDensityTextureNode(); - ShaderNode *clone() const; - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - - bool has_spatial_varying() { return true; } - bool has_object_dependency() { return true; } - - void add_image(); - - ustring filename; - NodeTexVoxelSpace space; - InterpolationType interpolation; - Transform tfm; - float3 vector; - - ImageManager *image_manager; - int slot; - void *builtin_data; - - virtual bool equals(const ShaderNode& other) { - const PointDensityTextureNode& point_dendity_node = (const PointDensityTextureNode&)other; - return ShaderNode::equals(other) && - builtin_data == point_dendity_node.builtin_data; - } + public: + SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } + + ~PointDensityTextureNode(); + ShaderNode *clone() const; + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + + bool has_spatial_varying() + { + return true; + } + bool has_object_dependency() + { + return true; + } + + void add_image(); + + ustring filename; + NodeTexVoxelSpace space; + InterpolationType interpolation; + Transform tfm; + float3 vector; + + ImageManager *image_manager; + int slot; + void *builtin_data; + + virtual bool equals(const ShaderNode &other) + { + const PointDensityTextureNode &point_dendity_node = (const PointDensityTextureNode &)other; + return ShaderNode::equals(other) && builtin_data == point_dendity_node.builtin_data; + } }; class IESLightNode : public TextureNode { -public: - SHADER_NODE_NO_CLONE_CLASS(IESLightNode) + public: + SHADER_NODE_NO_CLONE_CLASS(IESLightNode) - ~IESLightNode(); - ShaderNode *clone() const; - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + ~IESLightNode(); + ShaderNode *clone() const; + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - ustring filename; - ustring ies; + ustring filename; + ustring ies; - float strength; - float3 vector; + float strength; + float3 vector; -private: - LightManager *light_manager; - int slot; + private: + LightManager *light_manager; + int slot; - void get_slot(); + void get_slot(); }; class MappingNode : public ShaderNode { -public: - SHADER_NODE_CLASS(MappingNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + public: + SHADER_NODE_CLASS(MappingNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - float3 vector; - TextureMapping tex_mapping; + float3 vector; + TextureMapping tex_mapping; }; class RGBToBWNode : public ShaderNode { -public: - SHADER_NODE_CLASS(RGBToBWNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(RGBToBWNode) + void constant_fold(const ConstantFolder &folder); - float3 color; + float3 color; }; class ConvertNode : public ShaderNode { -public: - ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); - SHADER_NODE_BASE_CLASS(ConvertNode) + public: + ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); + SHADER_NODE_BASE_CLASS(ConvertNode) - void constant_fold(const ConstantFolder& folder); + void constant_fold(const ConstantFolder &folder); - SocketType::Type from, to; + SocketType::Type from, to; - union { - float value_float; - int value_int; - float3 value_color; - float3 value_vector; - float3 value_point; - float3 value_normal; - }; - ustring value_string; + union { + float value_float; + int value_int; + float3 value_color; + float3 value_vector; + float3 value_point; + float3 value_normal; + }; + ustring value_string; -private: - static const int MAX_TYPE = 12; - static bool register_types(); - static Node* create(const NodeType *type); - static const NodeType *node_types[MAX_TYPE][MAX_TYPE]; - static bool initialized; + private: + static const int MAX_TYPE = 12; + static bool register_types(); + static Node *create(const NodeType *type); + static const NodeType *node_types[MAX_TYPE][MAX_TYPE]; + static bool initialized; }; class BsdfBaseNode : public ShaderNode { -public: - BsdfBaseNode(const NodeType *node_type); + public: + BsdfBaseNode(const NodeType *node_type); - bool has_spatial_varying() { return true; } - virtual ClosureType get_closure_type() { return closure; } - virtual bool has_bump(); + bool has_spatial_varying() + { + return true; + } + virtual ClosureType get_closure_type() + { + return closure; + } + virtual bool has_bump(); - virtual bool equals(const ShaderNode& /*other*/) - { - /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ - return false; - } + virtual bool equals(const ShaderNode & /*other*/) + { + /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */ + return false; + } - ClosureType closure; + ClosureType closure; }; class BsdfNode : public BsdfBaseNode { -public: - explicit BsdfNode(const NodeType *node_type); - SHADER_NODE_BASE_CLASS(BsdfNode) + public: + explicit BsdfNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(BsdfNode) - void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL); + void compile(SVMCompiler &compiler, + ShaderInput *param1, + ShaderInput *param2, + ShaderInput *param3 = NULL, + ShaderInput *param4 = NULL); - float3 color; - float3 normal; - float surface_mix_weight; + float3 color; + float3 normal; + float surface_mix_weight; }; class AnisotropicBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(AnisotropicBsdfNode) + public: + SHADER_NODE_CLASS(AnisotropicBsdfNode) - float3 tangent; - float roughness, anisotropy, rotation; - ClosureType distribution; + float3 tangent; + float roughness, anisotropy, rotation; + ClosureType distribution; - ClosureType get_closure_type() { return distribution; } - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } + ClosureType get_closure_type() + { + return distribution; + } + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } }; class DiffuseBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(DiffuseBsdfNode) + public: + SHADER_NODE_CLASS(DiffuseBsdfNode) - float roughness; + float roughness; }; /* Disney principled BRDF */ class PrincipledBsdfNode : public BsdfBaseNode { -public: - SHADER_NODE_CLASS(PrincipledBsdfNode) - - bool has_surface_bssrdf(); - bool has_bssrdf_bump(); - void compile(SVMCompiler& compiler, ShaderInput *metallic, ShaderInput *subsurface, ShaderInput *subsurface_radius, - ShaderInput *specular, ShaderInput *roughness, ShaderInput *specular_tint, ShaderInput *anisotropic, - ShaderInput *sheen, ShaderInput *sheen_tint, ShaderInput *clearcoat, ShaderInput *clearcoat_roughness, - ShaderInput *ior, ShaderInput *transmission, ShaderInput *anisotropic_rotation, ShaderInput *transmission_roughness); - - float3 base_color; - float3 subsurface_color, subsurface_radius; - float metallic, subsurface, specular, roughness, specular_tint, anisotropic, - sheen, sheen_tint, clearcoat, clearcoat_roughness, ior, transmission, - anisotropic_rotation, transmission_roughness; - float3 normal, clearcoat_normal, tangent; - float surface_mix_weight; - ClosureType distribution, distribution_orig; - ClosureType subsurface_method; - - bool has_integrator_dependency(); - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } + public: + SHADER_NODE_CLASS(PrincipledBsdfNode) + + bool has_surface_bssrdf(); + bool has_bssrdf_bump(); + void compile(SVMCompiler &compiler, + ShaderInput *metallic, + ShaderInput *subsurface, + ShaderInput *subsurface_radius, + ShaderInput *specular, + ShaderInput *roughness, + ShaderInput *specular_tint, + ShaderInput *anisotropic, + ShaderInput *sheen, + ShaderInput *sheen_tint, + ShaderInput *clearcoat, + ShaderInput *clearcoat_roughness, + ShaderInput *ior, + ShaderInput *transmission, + ShaderInput *anisotropic_rotation, + ShaderInput *transmission_roughness); + + float3 base_color; + float3 subsurface_color, subsurface_radius; + float metallic, subsurface, specular, roughness, specular_tint, anisotropic, sheen, sheen_tint, + clearcoat, clearcoat_roughness, ior, transmission, anisotropic_rotation, + transmission_roughness; + float3 normal, clearcoat_normal, tangent; + float surface_mix_weight; + ClosureType distribution, distribution_orig; + ClosureType subsurface_method; + + bool has_integrator_dependency(); + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } }; class TranslucentBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(TranslucentBsdfNode) + public: + SHADER_NODE_CLASS(TranslucentBsdfNode) }; class TransparentBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(TransparentBsdfNode) + public: + SHADER_NODE_CLASS(TransparentBsdfNode) - bool has_surface_transparent() { return true; } + bool has_surface_transparent() + { + return true; + } }; class VelvetBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(VelvetBsdfNode) + public: + SHADER_NODE_CLASS(VelvetBsdfNode) - float sigma; + float sigma; }; class GlossyBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(GlossyBsdfNode) + public: + SHADER_NODE_CLASS(GlossyBsdfNode) - void simplify_settings(Scene *scene); - bool has_integrator_dependency(); - ClosureType get_closure_type() { return distribution; } + void simplify_settings(Scene *scene); + bool has_integrator_dependency(); + ClosureType get_closure_type() + { + return distribution; + } - float roughness, roughness_orig; - ClosureType distribution, distribution_orig; + float roughness, roughness_orig; + ClosureType distribution, distribution_orig; }; class GlassBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(GlassBsdfNode) + public: + SHADER_NODE_CLASS(GlassBsdfNode) - void simplify_settings(Scene *scene); - bool has_integrator_dependency(); - ClosureType get_closure_type() { return distribution; } + void simplify_settings(Scene *scene); + bool has_integrator_dependency(); + ClosureType get_closure_type() + { + return distribution; + } - float roughness, roughness_orig, IOR; - ClosureType distribution, distribution_orig; + float roughness, roughness_orig, IOR; + ClosureType distribution, distribution_orig; }; class RefractionBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(RefractionBsdfNode) + public: + SHADER_NODE_CLASS(RefractionBsdfNode) - void simplify_settings(Scene *scene); - bool has_integrator_dependency(); - ClosureType get_closure_type() { return distribution; } + void simplify_settings(Scene *scene); + bool has_integrator_dependency(); + ClosureType get_closure_type() + { + return distribution; + } - float roughness, roughness_orig, IOR; - ClosureType distribution, distribution_orig; + float roughness, roughness_orig, IOR; + ClosureType distribution, distribution_orig; }; class ToonBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(ToonBsdfNode) + public: + SHADER_NODE_CLASS(ToonBsdfNode) - float smooth, size; - ClosureType component; + float smooth, size; + ClosureType component; }; class SubsurfaceScatteringNode : public BsdfNode { -public: - SHADER_NODE_CLASS(SubsurfaceScatteringNode) - bool has_surface_bssrdf() { return true; } - bool has_bssrdf_bump(); - ClosureType get_closure_type() { return falloff; } - - float scale; - float3 radius; - float sharpness; - float texture_blur; - ClosureType falloff; + public: + SHADER_NODE_CLASS(SubsurfaceScatteringNode) + bool has_surface_bssrdf() + { + return true; + } + bool has_bssrdf_bump(); + ClosureType get_closure_type() + { + return falloff; + } + + float scale; + float3 radius; + float sharpness; + float texture_blur; + ClosureType falloff; }; class EmissionNode : public ShaderNode { -public: - SHADER_NODE_CLASS(EmissionNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(EmissionNode) + void constant_fold(const ConstantFolder &folder); - bool has_surface_emission() { return true; } - bool has_volume_support() { return true; } + bool has_surface_emission() + { + return true; + } + bool has_volume_support() + { + return true; + } - float3 color; - float strength; - float surface_mix_weight; + float3 color; + float strength; + float surface_mix_weight; }; class BackgroundNode : public ShaderNode { -public: - SHADER_NODE_CLASS(BackgroundNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(BackgroundNode) + void constant_fold(const ConstantFolder &folder); - float3 color; - float strength; - float surface_mix_weight; + float3 color; + float strength; + float surface_mix_weight; }; class HoldoutNode : public ShaderNode { -public: - SHADER_NODE_CLASS(HoldoutNode) - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - virtual ClosureType get_closure_type() { return CLOSURE_HOLDOUT_ID; } + public: + SHADER_NODE_CLASS(HoldoutNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } + virtual ClosureType get_closure_type() + { + return CLOSURE_HOLDOUT_ID; + } - float surface_mix_weight; - float volume_mix_weight; + float surface_mix_weight; + float volume_mix_weight; }; class AmbientOcclusionNode : public ShaderNode { -public: - SHADER_NODE_CLASS(AmbientOcclusionNode) - - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - virtual bool has_raytrace() { return true; } - - float3 color; - float distance; - float3 normal; - int samples; - - bool only_local; - bool inside; + public: + SHADER_NODE_CLASS(AmbientOcclusionNode) + + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } + virtual bool has_raytrace() + { + return true; + } + + float3 color; + float distance; + float3 normal; + int samples; + + bool only_local; + bool inside; }; class VolumeNode : public ShaderNode { -public: - VolumeNode(const NodeType *node_type); - SHADER_NODE_BASE_CLASS(VolumeNode) - - void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2); - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - virtual int get_feature() { - return ShaderNode::get_feature() | NODE_FEATURE_VOLUME; - } - virtual ClosureType get_closure_type() { return closure; } - virtual bool has_volume_support() { return true; } - - float3 color; - float density; - float volume_mix_weight; - ClosureType closure; - - virtual bool equals(const ShaderNode& /*other*/) - { - /* TODO(sergey): With some care Volume nodes can be de-duplicated. */ - return false; - } + public: + VolumeNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(VolumeNode) + + void compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2); + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } + virtual int get_feature() + { + return ShaderNode::get_feature() | NODE_FEATURE_VOLUME; + } + virtual ClosureType get_closure_type() + { + return closure; + } + virtual bool has_volume_support() + { + return true; + } + + float3 color; + float density; + float volume_mix_weight; + ClosureType closure; + + virtual bool equals(const ShaderNode & /*other*/) + { + /* TODO(sergey): With some care Volume nodes can be de-duplicated. */ + return false; + } }; class AbsorptionVolumeNode : public VolumeNode { -public: - SHADER_NODE_CLASS(AbsorptionVolumeNode) + public: + SHADER_NODE_CLASS(AbsorptionVolumeNode) }; class ScatterVolumeNode : public VolumeNode { -public: - SHADER_NODE_CLASS(ScatterVolumeNode) + public: + SHADER_NODE_CLASS(ScatterVolumeNode) - float anisotropy; + float anisotropy; }; class PrincipledVolumeNode : public VolumeNode { -public: - SHADER_NODE_CLASS(PrincipledVolumeNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - - ustring density_attribute; - ustring color_attribute; - ustring temperature_attribute; - - float anisotropy; - float3 absorption_color; - float emission_strength; - float3 emission_color; - float blackbody_intensity; - float3 blackbody_tint; - float temperature; + public: + SHADER_NODE_CLASS(PrincipledVolumeNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + + ustring density_attribute; + ustring color_attribute; + ustring temperature_attribute; + + float anisotropy; + float3 absorption_color; + float emission_strength; + float3 emission_color; + float blackbody_intensity; + float3 blackbody_tint; + float temperature; }; /* Interface between the I/O sockets and the SVM/OSL backend. */ class PrincipledHairBsdfNode : public BsdfBaseNode { -public: - SHADER_NODE_CLASS(PrincipledHairBsdfNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - - /* Longitudinal roughness. */ - float roughness; - /* Azimuthal roughness. */ - float radial_roughness; - /* Randomization factor for roughnesses. */ - float random_roughness; - /* Longitudinal roughness factor for only the diffuse bounce (shiny undercoat). */ - float coat; - /* Index of reflection. */ - float ior; - /* Cuticle tilt angle. */ - float offset; - /* Direct coloring's color. */ - float3 color; - /* Melanin concentration. */ - float melanin; - /* Melanin redness ratio. */ - float melanin_redness; - /* Dye color. */ - float3 tint; - /* Randomization factor for melanin quantities. */ - float random_color; - /* Absorption coefficient (unfiltered). */ - float3 absorption_coefficient; - - float3 normal; - float surface_mix_weight; - /* If linked, here will be the given random number. */ - float random; - /* Selected coloring parametrization. */ - NodePrincipledHairParametrization parametrization; + public: + SHADER_NODE_CLASS(PrincipledHairBsdfNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + + /* Longitudinal roughness. */ + float roughness; + /* Azimuthal roughness. */ + float radial_roughness; + /* Randomization factor for roughnesses. */ + float random_roughness; + /* Longitudinal roughness factor for only the diffuse bounce (shiny undercoat). */ + float coat; + /* Index of reflection. */ + float ior; + /* Cuticle tilt angle. */ + float offset; + /* Direct coloring's color. */ + float3 color; + /* Melanin concentration. */ + float melanin; + /* Melanin redness ratio. */ + float melanin_redness; + /* Dye color. */ + float3 tint; + /* Randomization factor for melanin quantities. */ + float random_color; + /* Absorption coefficient (unfiltered). */ + float3 absorption_coefficient; + + float3 normal; + float surface_mix_weight; + /* If linked, here will be the given random number. */ + float random; + /* Selected coloring parametrization. */ + NodePrincipledHairParametrization parametrization; }; class HairBsdfNode : public BsdfNode { -public: - SHADER_NODE_CLASS(HairBsdfNode) - ClosureType get_closure_type() { return component; } + public: + SHADER_NODE_CLASS(HairBsdfNode) + ClosureType get_closure_type() + { + return component; + } - ClosureType component; - float offset; - float roughness_u; - float roughness_v; - float3 tangent; + ClosureType component; + float offset; + float roughness_u; + float roughness_v; + float3 tangent; }; class GeometryNode : public ShaderNode { -public: - SHADER_NODE_CLASS(GeometryNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } - int get_group(); - - float3 normal_osl; + public: + SHADER_NODE_CLASS(GeometryNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } + int get_group(); + + float3 normal_osl; }; class TextureCoordinateNode : public ShaderNode { -public: - SHADER_NODE_CLASS(TextureCoordinateNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } - bool has_object_dependency() { return use_transform; } - - float3 normal_osl; - bool from_dupli; - bool use_transform; - Transform ob_tfm; + public: + SHADER_NODE_CLASS(TextureCoordinateNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } + bool has_object_dependency() + { + return use_transform; + } + + float3 normal_osl; + bool from_dupli; + bool use_transform; + Transform ob_tfm; }; class UVMapNode : public ShaderNode { -public: - SHADER_NODE_CLASS(UVMapNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - - ustring attribute; - bool from_dupli; + public: + SHADER_NODE_CLASS(UVMapNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } + + ustring attribute; + bool from_dupli; }; class LightPathNode : public ShaderNode { -public: - SHADER_NODE_CLASS(LightPathNode) - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(LightPathNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } }; class LightFalloffNode : public ShaderNode { -public: - SHADER_NODE_CLASS(LightFalloffNode) - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + public: + SHADER_NODE_CLASS(LightFalloffNode) + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - float strength; - float smooth; + float strength; + float smooth; }; class ObjectInfoNode : public ShaderNode { -public: - SHADER_NODE_CLASS(ObjectInfoNode) - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(ObjectInfoNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } }; class ParticleInfoNode : public ShaderNode { -public: - SHADER_NODE_CLASS(ParticleInfoNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(ParticleInfoNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } }; class HairInfoNode : public ShaderNode { -public: - SHADER_NODE_CLASS(HairInfoNode) - - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - virtual int get_feature() { - return ShaderNode::get_feature() | NODE_FEATURE_HAIR; - } + public: + SHADER_NODE_CLASS(HairInfoNode) + + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } + virtual int get_feature() + { + return ShaderNode::get_feature() | NODE_FEATURE_HAIR; + } }; class ValueNode : public ShaderNode { -public: - SHADER_NODE_CLASS(ValueNode) + public: + SHADER_NODE_CLASS(ValueNode) - void constant_fold(const ConstantFolder& folder); + void constant_fold(const ConstantFolder &folder); - float value; + float value; }; class ColorNode : public ShaderNode { -public: - SHADER_NODE_CLASS(ColorNode) + public: + SHADER_NODE_CLASS(ColorNode) - void constant_fold(const ConstantFolder& folder); + void constant_fold(const ConstantFolder &folder); - float3 value; + float3 value; }; class AddClosureNode : public ShaderNode { -public: - SHADER_NODE_CLASS(AddClosureNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(AddClosureNode) + void constant_fold(const ConstantFolder &folder); }; class MixClosureNode : public ShaderNode { -public: - SHADER_NODE_CLASS(MixClosureNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(MixClosureNode) + void constant_fold(const ConstantFolder &folder); - float fac; + float fac; }; class MixClosureWeightNode : public ShaderNode { -public: - SHADER_NODE_CLASS(MixClosureWeightNode) + public: + SHADER_NODE_CLASS(MixClosureWeightNode) - float weight; - float fac; + float weight; + float fac; }; class InvertNode : public ShaderNode { -public: - SHADER_NODE_CLASS(InvertNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(InvertNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float fac; - float3 color; + float fac; + float3 color; }; class MixNode : public ShaderNode { -public: - SHADER_NODE_CLASS(MixNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(MixNode) + void constant_fold(const ConstantFolder &folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - NodeMix type; - bool use_clamp; - float3 color1; - float3 color2; - float fac; + NodeMix type; + bool use_clamp; + float3 color1; + float3 color2; + float fac; }; class CombineRGBNode : public ShaderNode { -public: - SHADER_NODE_CLASS(CombineRGBNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(CombineRGBNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float r, g, b; + float r, g, b; }; class CombineHSVNode : public ShaderNode { -public: - SHADER_NODE_CLASS(CombineHSVNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(CombineHSVNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float h, s, v; + float h, s, v; }; class CombineXYZNode : public ShaderNode { -public: - SHADER_NODE_CLASS(CombineXYZNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(CombineXYZNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float x, y, z; + float x, y, z; }; class GammaNode : public ShaderNode { -public: - SHADER_NODE_CLASS(GammaNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(GammaNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } - float3 color; - float gamma; + float3 color; + float gamma; }; class BrightContrastNode : public ShaderNode { -public: - SHADER_NODE_CLASS(BrightContrastNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(BrightContrastNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } - float3 color; - float bright; - float contrast; + float3 color; + float bright; + float contrast; }; class SeparateRGBNode : public ShaderNode { -public: - SHADER_NODE_CLASS(SeparateRGBNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(SeparateRGBNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float3 color; + float3 color; }; class SeparateHSVNode : public ShaderNode { -public: - SHADER_NODE_CLASS(SeparateHSVNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(SeparateHSVNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float3 color; + float3 color; }; class SeparateXYZNode : public ShaderNode { -public: - SHADER_NODE_CLASS(SeparateXYZNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(SeparateXYZNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float3 vector; + float3 vector; }; class HSVNode : public ShaderNode { -public: - SHADER_NODE_CLASS(HSVNode) + public: + SHADER_NODE_CLASS(HSVNode) - float hue; - float saturation; - float value; - float fac; - float3 color; + float hue; + float saturation; + float value; + float fac; + float3 color; }; class AttributeNode : public ShaderNode { -public: - SHADER_NODE_CLASS(AttributeNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } + public: + SHADER_NODE_CLASS(AttributeNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } - ustring attribute; + ustring attribute; }; class CameraNode : public ShaderNode { -public: - SHADER_NODE_CLASS(CameraNode) - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + public: + SHADER_NODE_CLASS(CameraNode) + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } }; class FresnelNode : public ShaderNode { -public: - SHADER_NODE_CLASS(FresnelNode) - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(FresnelNode) + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } - float3 normal; - float IOR; + float3 normal; + float IOR; }; class LayerWeightNode : public ShaderNode { -public: - SHADER_NODE_CLASS(LayerWeightNode) - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(LayerWeightNode) + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } - float3 normal; - float blend; + float3 normal; + float blend; }; class WireframeNode : public ShaderNode { -public: - SHADER_NODE_CLASS(WireframeNode) - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(WireframeNode) + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float size; - bool use_pixel_size; + float size; + bool use_pixel_size; }; class WavelengthNode : public ShaderNode { -public: - SHADER_NODE_CLASS(WavelengthNode) - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(WavelengthNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float wavelength; + float wavelength; }; class BlackbodyNode : public ShaderNode { -public: - SHADER_NODE_CLASS(BlackbodyNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + public: + SHADER_NODE_CLASS(BlackbodyNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - float temperature; + float temperature; }; class MathNode : public ShaderNode { -public: - SHADER_NODE_CLASS(MathNode) - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(MathNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } + void constant_fold(const ConstantFolder &folder); - float value1; - float value2; - NodeMath type; - bool use_clamp; + float value1; + float value2; + NodeMath type; + bool use_clamp; }; class NormalNode : public ShaderNode { -public: - SHADER_NODE_CLASS(NormalNode) - virtual int get_group() { return NODE_GROUP_LEVEL_2; } + public: + SHADER_NODE_CLASS(NormalNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_2; + } - float3 direction; - float3 normal; + float3 direction; + float3 normal; }; class VectorMathNode : public ShaderNode { -public: - SHADER_NODE_CLASS(VectorMathNode) - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(VectorMathNode) + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } + void constant_fold(const ConstantFolder &folder); - float3 vector1; - float3 vector2; - NodeVectorMath type; + float3 vector1; + float3 vector2; + NodeVectorMath type; }; class VectorTransformNode : public ShaderNode { -public: - SHADER_NODE_CLASS(VectorTransformNode) + public: + SHADER_NODE_CLASS(VectorTransformNode) - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - NodeVectorTransformType type; - NodeVectorTransformConvertSpace convert_from; - NodeVectorTransformConvertSpace convert_to; - float3 vector; + NodeVectorTransformType type; + NodeVectorTransformConvertSpace convert_from; + NodeVectorTransformConvertSpace convert_to; + float3 vector; }; class BumpNode : public ShaderNode { -public: - SHADER_NODE_CLASS(BumpNode) - void constant_fold(const ConstantFolder& folder); - bool has_spatial_varying() { return true; } - virtual int get_feature() { - return NODE_FEATURE_BUMP; - } - - bool invert; - bool use_object_space; - float height; - float sample_center; - float sample_x; - float sample_y; - float3 normal; - float strength; - float distance; + public: + SHADER_NODE_CLASS(BumpNode) + void constant_fold(const ConstantFolder &folder); + bool has_spatial_varying() + { + return true; + } + virtual int get_feature() + { + return NODE_FEATURE_BUMP; + } + + bool invert; + bool use_object_space; + float height; + float sample_center; + float sample_x; + float sample_y; + float3 normal; + float strength; + float distance; }; class CurvesNode : public ShaderNode { -public: - explicit CurvesNode(const NodeType *node_type); - SHADER_NODE_BASE_CLASS(CurvesNode) + public: + explicit CurvesNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(CurvesNode) - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } - array<float3> curves; - float min_x, max_x, fac; - float3 value; + array<float3> curves; + float min_x, max_x, fac; + float3 value; -protected: - using ShaderNode::constant_fold; - void constant_fold(const ConstantFolder& folder, ShaderInput *value_in); - void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out); - void compile(OSLCompiler& compiler, const char *name); + protected: + using ShaderNode::constant_fold; + void constant_fold(const ConstantFolder &folder, ShaderInput *value_in); + void compile(SVMCompiler &compiler, int type, ShaderInput *value_in, ShaderOutput *value_out); + void compile(OSLCompiler &compiler, const char *name); }; class RGBCurvesNode : public CurvesNode { -public: - SHADER_NODE_CLASS(RGBCurvesNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(RGBCurvesNode) + void constant_fold(const ConstantFolder &folder); }; class VectorCurvesNode : public CurvesNode { -public: - SHADER_NODE_CLASS(VectorCurvesNode) - void constant_fold(const ConstantFolder& folder); + public: + SHADER_NODE_CLASS(VectorCurvesNode) + void constant_fold(const ConstantFolder &folder); }; class RGBRampNode : public ShaderNode { -public: - SHADER_NODE_CLASS(RGBRampNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_group() { return NODE_GROUP_LEVEL_1; } + public: + SHADER_NODE_CLASS(RGBRampNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_group() + { + return NODE_GROUP_LEVEL_1; + } - array<float3> ramp; - array<float> ramp_alpha; - float fac; - bool interpolate; + array<float3> ramp; + array<float> ramp_alpha; + float fac; + bool interpolate; }; class SetNormalNode : public ShaderNode { -public: - SHADER_NODE_CLASS(SetNormalNode) - float3 direction; + public: + SHADER_NODE_CLASS(SetNormalNode) + float3 direction; }; class OSLNode : public ShaderNode { -public: - static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL); - ~OSLNode(); + public: + static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL); + ~OSLNode(); - ShaderNode *clone() const; + ShaderNode *clone() const; - char* input_default_value(); - void add_input(ustring name, SocketType::Type type); - void add_output(ustring name, SocketType::Type type); + char *input_default_value(); + void add_input(ustring name, SocketType::Type type); + void add_output(ustring name, SocketType::Type type); - SHADER_NODE_NO_CLONE_CLASS(OSLNode) + SHADER_NODE_NO_CLONE_CLASS(OSLNode) - /* ideally we could beter detect this, but we can't query this now */ - bool has_spatial_varying() { return true; } - bool has_volume_support() { return true; } + /* ideally we could beter detect this, but we can't query this now */ + bool has_spatial_varying() + { + return true; + } + bool has_volume_support() + { + return true; + } - virtual bool equals(const ShaderNode& /*other*/) { return false; } + virtual bool equals(const ShaderNode & /*other*/) + { + return false; + } - string filepath; - string bytecode_hash; + string filepath; + string bytecode_hash; }; class NormalMapNode : public ShaderNode { -public: - SHADER_NODE_CLASS(NormalMapNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - - NodeNormalMapSpace space; - ustring attribute; - float strength; - float3 color; - float3 normal_osl; + public: + SHADER_NODE_CLASS(NormalMapNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } + + NodeNormalMapSpace space; + ustring attribute; + float strength; + float3 color; + float3 normal_osl; }; class TangentNode : public ShaderNode { -public: - SHADER_NODE_CLASS(TangentNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - - NodeTangentDirectionType direction_type; - NodeTangentAxis axis; - ustring attribute; - float3 normal_osl; + public: + SHADER_NODE_CLASS(TangentNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } + + NodeTangentDirectionType direction_type; + NodeTangentAxis axis; + ustring attribute; + float3 normal_osl; }; class BevelNode : public ShaderNode { -public: - SHADER_NODE_CLASS(BevelNode) - bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_3; } - virtual bool has_raytrace() { return true; } - - float radius; - float3 normal; - int samples; + public: + SHADER_NODE_CLASS(BevelNode) + bool has_spatial_varying() + { + return true; + } + virtual int get_group() + { + return NODE_GROUP_LEVEL_3; + } + virtual bool has_raytrace() + { + return true; + } + + float radius; + float3 normal; + int samples; }; class DisplacementNode : public ShaderNode { -public: - SHADER_NODE_CLASS(DisplacementNode) - void constant_fold(const ConstantFolder& folder); - virtual int get_feature() { - return NODE_FEATURE_BUMP; - } + public: + SHADER_NODE_CLASS(DisplacementNode) + void constant_fold(const ConstantFolder &folder); + virtual int get_feature() + { + return NODE_FEATURE_BUMP; + } - NodeNormalMapSpace space; - float height; - float midlevel; - float scale; - float3 normal; + NodeNormalMapSpace space; + float height; + float midlevel; + float scale; + float3 normal; }; class VectorDisplacementNode : public ShaderNode { -public: - SHADER_NODE_CLASS(VectorDisplacementNode) - void attributes(Shader *shader, AttributeRequestSet *attributes); - bool has_attribute_dependency() { return true; } - void constant_fold(const ConstantFolder& folder); - virtual int get_feature() { - return NODE_FEATURE_BUMP; - } - - NodeNormalMapSpace space; - ustring attribute; - float3 vector; - float midlevel; - float scale; + public: + SHADER_NODE_CLASS(VectorDisplacementNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + bool has_attribute_dependency() + { + return true; + } + void constant_fold(const ConstantFolder &folder); + virtual int get_feature() + { + return NODE_FEATURE_BUMP; + } + + NodeNormalMapSpace space; + ustring attribute; + float3 vector; + float midlevel; + float scale; }; CCL_NAMESPACE_END -#endif /* __NODES_H__ */ +#endif /* __NODES_H__ */ diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index b34d16c438b..6c6f8810412 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -38,77 +38,76 @@ CCL_NAMESPACE_BEGIN /* Global state of object transform update. */ struct UpdateObjectTransformState { - /* Global state used by device_update_object_transform(). - * Common for both threaded and non-threaded update. - */ + /* Global state used by device_update_object_transform(). + * Common for both threaded and non-threaded update. + */ - /* Type of the motion required by the scene settings. */ - Scene::MotionType need_motion; + /* Type of the motion required by the scene settings. */ + Scene::MotionType need_motion; - /* Mapping from particle system to a index in packed particle array. - * Only used for read. - */ - map<ParticleSystem*, int> particle_offset; + /* Mapping from particle system to a index in packed particle array. + * Only used for read. + */ + map<ParticleSystem *, int> particle_offset; - /* Mesh area. - * Used to avoid calculation of mesh area multiple times. Used for both - * read and write. Acquire surface_area_lock to keep it all thread safe. - */ - map<Mesh*, float> surface_area_map; + /* Mesh area. + * Used to avoid calculation of mesh area multiple times. Used for both + * read and write. Acquire surface_area_lock to keep it all thread safe. + */ + map<Mesh *, float> surface_area_map; - /* Motion offsets for each object. */ - array<uint> motion_offset; + /* Motion offsets for each object. */ + array<uint> motion_offset; - /* Packed object arrays. Those will be filled in. */ - uint *object_flag; - KernelObject *objects; - Transform *object_motion_pass; - DecomposedTransform *object_motion; + /* Packed object arrays. Those will be filled in. */ + uint *object_flag; + KernelObject *objects; + Transform *object_motion_pass; + DecomposedTransform *object_motion; - /* Flags which will be synchronized to Integrator. */ - bool have_motion; - bool have_curves; + /* Flags which will be synchronized to Integrator. */ + bool have_motion; + bool have_curves; - /* ** Scheduling queue. ** */ + /* ** Scheduling queue. ** */ - Scene *scene; + Scene *scene; - /* Some locks to keep everything thread-safe. */ - thread_spin_lock queue_lock; - thread_spin_lock surface_area_lock; + /* Some locks to keep everything thread-safe. */ + thread_spin_lock queue_lock; + thread_spin_lock surface_area_lock; - /* First unused object index in the queue. */ - int queue_start_object; + /* First unused object index in the queue. */ + int queue_start_object; }; /* Object */ NODE_DEFINE(Object) { - NodeType* type = NodeType::add("object", create); - - SOCKET_NODE(mesh, "Mesh", &Mesh::node_type); - SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); - SOCKET_UINT(visibility, "Visibility", ~0); - SOCKET_UINT(random_id, "Random ID", 0); - SOCKET_INT(pass_id, "Pass ID", 0); - SOCKET_BOOLEAN(use_holdout, "Use Holdout", false); - SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false); - SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f)); - SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>()); - - SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false); - - return type; + NodeType *type = NodeType::add("object", create); + + SOCKET_NODE(mesh, "Mesh", &Mesh::node_type); + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + SOCKET_UINT(visibility, "Visibility", ~0); + SOCKET_UINT(random_id, "Random ID", 0); + SOCKET_INT(pass_id, "Pass ID", 0); + SOCKET_BOOLEAN(use_holdout, "Use Holdout", false); + SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false); + SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f)); + SOCKET_TRANSFORM_ARRAY(motion, "Motion", array<Transform>()); + + SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", false); + + return type; } -Object::Object() -: Node(node_type) +Object::Object() : Node(node_type) { - particle_system = NULL; - particle_index = 0; - bounds = BoundBox::empty; + particle_system = NULL; + particle_index = 0; + bounds = BoundBox::empty; } Object::~Object() @@ -117,768 +116,762 @@ Object::~Object() void Object::update_motion() { - if(!use_motion()) { - return; - } - - bool have_motion = false; - - for(size_t i = 0; i < motion.size(); i++) { - if(motion[i] == transform_empty()) { - if(hide_on_missing_motion) { - /* Hide objects that have no valid previous or next - * transform, for example particle that stop existing. It - * would be better to handle this in the kernel and make - * objects invisible outside certain motion steps. */ - tfm = transform_empty(); - motion.clear(); - return; - } - else { - /* Otherwise just copy center motion. */ - motion[i] = tfm; - } - } - - /* Test if any of the transforms are actually different. */ - have_motion = have_motion || motion[i] != tfm; - } - - /* Clear motion array if there is no actual motion. */ - if(!have_motion) { - motion.clear(); - } + if (!use_motion()) { + return; + } + + bool have_motion = false; + + for (size_t i = 0; i < motion.size(); i++) { + if (motion[i] == transform_empty()) { + if (hide_on_missing_motion) { + /* Hide objects that have no valid previous or next + * transform, for example particle that stop existing. It + * would be better to handle this in the kernel and make + * objects invisible outside certain motion steps. */ + tfm = transform_empty(); + motion.clear(); + return; + } + else { + /* Otherwise just copy center motion. */ + motion[i] = tfm; + } + } + + /* Test if any of the transforms are actually different. */ + have_motion = have_motion || motion[i] != tfm; + } + + /* Clear motion array if there is no actual motion. */ + if (!have_motion) { + motion.clear(); + } } void Object::compute_bounds(bool motion_blur) { - BoundBox mbounds = mesh->bounds; - - if(motion_blur && use_motion()) { - array<DecomposedTransform> decomp(motion.size()); - transform_motion_decompose(decomp.data(), motion.data(), motion.size()); - - bounds = BoundBox::empty; - - /* todo: this is really terrible. according to pbrt there is a better - * way to find this iteratively, but did not find implementation yet - * or try to implement myself */ - for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) { - Transform ttfm; - - transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t); - bounds.grow(mbounds.transformed(&ttfm)); - } - } - else { - /* No motion blur case. */ - if(mesh->transform_applied) { - bounds = mbounds; - } - else { - bounds = mbounds.transformed(&tfm); - } - } + BoundBox mbounds = mesh->bounds; + + if (motion_blur && use_motion()) { + array<DecomposedTransform> decomp(motion.size()); + transform_motion_decompose(decomp.data(), motion.data(), motion.size()); + + bounds = BoundBox::empty; + + /* todo: this is really terrible. according to pbrt there is a better + * way to find this iteratively, but did not find implementation yet + * or try to implement myself */ + for (float t = 0.0f; t < 1.0f; t += (1.0f / 128.0f)) { + Transform ttfm; + + transform_motion_array_interpolate(&ttfm, decomp.data(), motion.size(), t); + bounds.grow(mbounds.transformed(&ttfm)); + } + } + else { + /* No motion blur case. */ + if (mesh->transform_applied) { + bounds = mbounds; + } + else { + bounds = mbounds.transformed(&tfm); + } + } } void Object::apply_transform(bool apply_to_motion) { - if(!mesh || tfm == transform_identity()) - return; - - /* triangles */ - if(mesh->verts.size()) { - /* store matrix to transform later. when accessing these as attributes we - * do not want the transform to be applied for consistency between static - * and dynamic BVH, so we do it on packing. */ - mesh->transform_normal = transform_transposed_inverse(tfm); - - /* apply to mesh vertices */ - for(size_t i = 0; i < mesh->verts.size(); i++) - mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); - - if(apply_to_motion) { - Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr) { - size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); - float3 *vert_steps = attr->data_float3(); - - for(size_t i = 0; i < steps_size; i++) - vert_steps[i] = transform_point(&tfm, vert_steps[i]); - } - - Attribute *attr_N = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - - if(attr_N) { - Transform ntfm = mesh->transform_normal; - size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); - float3 *normal_steps = attr_N->data_float3(); - - for(size_t i = 0; i < steps_size; i++) - normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i])); - } - } - } - - /* curves */ - if(mesh->curve_keys.size()) { - /* compute uniform scale */ - float3 c0 = transform_get_column(&tfm, 0); - float3 c1 = transform_get_column(&tfm, 1); - float3 c2 = transform_get_column(&tfm, 2); - float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f/3.0f); - - /* apply transform to curve keys */ - for(size_t i = 0; i < mesh->curve_keys.size(); i++) { - float3 co = transform_point(&tfm, mesh->curve_keys[i]); - float radius = mesh->curve_radius[i] * scalar; - - /* scale for curve radius is only correct for uniform scale */ - mesh->curve_keys[i] = co; - mesh->curve_radius[i] = radius; - } - - if(apply_to_motion) { - Attribute *curve_attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(curve_attr) { - /* apply transform to motion curve keys */ - size_t steps_size = mesh->curve_keys.size() * (mesh->motion_steps - 1); - float4 *key_steps = curve_attr->data_float4(); - - for(size_t i = 0; i < steps_size; i++) { - float3 co = transform_point(&tfm, float4_to_float3(key_steps[i])); - float radius = key_steps[i].w * scalar; - - /* scale for curve radius is only correct for uniform scale */ - key_steps[i] = float3_to_float4(co); - key_steps[i].w = radius; - } - } - } - } - - /* we keep normals pointing in same direction on negative scale, notify - * mesh about this in it (re)calculates normals */ - if(transform_negative_scale(tfm)) - mesh->transform_negative_scaled = true; - - if(bounds.valid()) { - mesh->compute_bounds(); - compute_bounds(false); - } - - /* tfm is not reset to identity, all code that uses it needs to check the - * transform_applied boolean */ + if (!mesh || tfm == transform_identity()) + return; + + /* triangles */ + if (mesh->verts.size()) { + /* store matrix to transform later. when accessing these as attributes we + * do not want the transform to be applied for consistency between static + * and dynamic BVH, so we do it on packing. */ + mesh->transform_normal = transform_transposed_inverse(tfm); + + /* apply to mesh vertices */ + for (size_t i = 0; i < mesh->verts.size(); i++) + mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); + + if (apply_to_motion) { + Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (attr) { + size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); + float3 *vert_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + vert_steps[i] = transform_point(&tfm, vert_steps[i]); + } + + Attribute *attr_N = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + + if (attr_N) { + Transform ntfm = mesh->transform_normal; + size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); + float3 *normal_steps = attr_N->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i])); + } + } + } + + /* curves */ + if (mesh->curve_keys.size()) { + /* compute uniform scale */ + float3 c0 = transform_get_column(&tfm, 0); + float3 c1 = transform_get_column(&tfm, 1); + float3 c2 = transform_get_column(&tfm, 2); + float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f); + + /* apply transform to curve keys */ + for (size_t i = 0; i < mesh->curve_keys.size(); i++) { + float3 co = transform_point(&tfm, mesh->curve_keys[i]); + float radius = mesh->curve_radius[i] * scalar; + + /* scale for curve radius is only correct for uniform scale */ + mesh->curve_keys[i] = co; + mesh->curve_radius[i] = radius; + } + + if (apply_to_motion) { + Attribute *curve_attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (curve_attr) { + /* apply transform to motion curve keys */ + size_t steps_size = mesh->curve_keys.size() * (mesh->motion_steps - 1); + float4 *key_steps = curve_attr->data_float4(); + + for (size_t i = 0; i < steps_size; i++) { + float3 co = transform_point(&tfm, float4_to_float3(key_steps[i])); + float radius = key_steps[i].w * scalar; + + /* scale for curve radius is only correct for uniform scale */ + key_steps[i] = float3_to_float4(co); + key_steps[i].w = radius; + } + } + } + } + + /* we keep normals pointing in same direction on negative scale, notify + * mesh about this in it (re)calculates normals */ + if (transform_negative_scale(tfm)) + mesh->transform_negative_scaled = true; + + if (bounds.valid()) { + mesh->compute_bounds(); + compute_bounds(false); + } + + /* tfm is not reset to identity, all code that uses it needs to check the + * transform_applied boolean */ } void Object::tag_update(Scene *scene) { - if(mesh) { - if(mesh->transform_applied) - mesh->need_update = true; - - foreach(Shader *shader, mesh->used_shaders) { - if(shader->use_mis && shader->has_surface_emission) - scene->light_manager->need_update = true; - } - } - - scene->camera->need_flags_update = true; - scene->curve_system_manager->need_update = true; - scene->mesh_manager->need_update = true; - scene->object_manager->need_update = true; + if (mesh) { + if (mesh->transform_applied) + mesh->need_update = true; + + foreach (Shader *shader, mesh->used_shaders) { + if (shader->use_mis && shader->has_surface_emission) + scene->light_manager->need_update = true; + } + } + + scene->camera->need_flags_update = true; + scene->curve_system_manager->need_update = true; + scene->mesh_manager->need_update = true; + scene->object_manager->need_update = true; } bool Object::use_motion() const { - return (motion.size() > 1); + return (motion.size() > 1); } float Object::motion_time(int step) const { - return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f; + return (use_motion()) ? 2.0f * step / (motion.size() - 1) - 1.0f : 0.0f; } int Object::motion_step(float time) const { - if(use_motion()) { - for(size_t step = 0; step < motion.size(); step++) { - if(time == motion_time(step)) { - return step; - } - } - } - - return -1; + if (use_motion()) { + for (size_t step = 0; step < motion.size(); step++) { + if (time == motion_time(step)) { + return step; + } + } + } + + return -1; } bool Object::is_traceable() const { - /* Mesh itself can be empty,can skip all such objects. */ - if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) { - return false; - } - /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */ - return true; + /* Mesh itself can be empty,can skip all such objects. */ + if (!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) { + return false; + } + /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */ + return true; } -uint Object::visibility_for_tracing() const { - uint trace_visibility = visibility; - if(is_shadow_catcher) { - trace_visibility &= ~PATH_RAY_SHADOW_NON_CATCHER; - } - else { - trace_visibility &= ~PATH_RAY_SHADOW_CATCHER; - } - return trace_visibility; +uint Object::visibility_for_tracing() const +{ + uint trace_visibility = visibility; + if (is_shadow_catcher) { + trace_visibility &= ~PATH_RAY_SHADOW_NON_CATCHER; + } + else { + trace_visibility &= ~PATH_RAY_SHADOW_CATCHER; + } + return trace_visibility; } int Object::get_device_index() const { - return index; + return index; } /* Object Manager */ ObjectManager::ObjectManager() { - need_update = true; - need_flags_update = true; + need_update = true; + need_flags_update = true; } ObjectManager::~ObjectManager() { } -void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, - Object *ob) +void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob) { - KernelObject& kobject = state->objects[ob->index]; - Transform *object_motion_pass = state->object_motion_pass; - - Mesh *mesh = ob->mesh; - uint flag = 0; - - /* Compute transformations. */ - Transform tfm = ob->tfm; - Transform itfm = transform_inverse(tfm); - - /* Compute surface area. for uniform scale we can do avoid the many - * transform calls and share computation for instances. - * - * TODO(brecht): Correct for displacement, and move to a better place. - */ - float uniform_scale; - float surface_area = 0.0f; - float pass_id = ob->pass_id; - float random_number = (float)ob->random_id * (1.0f/(float)0xFFFFFFFF); - int particle_index = (ob->particle_system) - ? ob->particle_index + state->particle_offset[ob->particle_system] - : 0; - - if(transform_uniform_scale(tfm, uniform_scale)) { - map<Mesh*, float>::iterator it; - - /* NOTE: This isn't fully optimal and could in theory lead to multiple - * threads calculating area of the same mesh in parallel. However, this - * also prevents suspending all the threads when some mesh's area is - * not yet known. - */ - state->surface_area_lock.lock(); - it = state->surface_area_map.find(mesh); - state->surface_area_lock.unlock(); - - if(it == state->surface_area_map.end()) { - size_t num_triangles = mesh->num_triangles(); - for(size_t j = 0; j < num_triangles; j++) { - Mesh::Triangle t = mesh->get_triangle(j); - float3 p1 = mesh->verts[t.v[0]]; - float3 p2 = mesh->verts[t.v[1]]; - float3 p3 = mesh->verts[t.v[2]]; - - surface_area += triangle_area(p1, p2, p3); - } - - state->surface_area_lock.lock(); - state->surface_area_map[mesh] = surface_area; - state->surface_area_lock.unlock(); - } - else { - surface_area = it->second; - } - - surface_area *= uniform_scale; - } - else { - size_t num_triangles = mesh->num_triangles(); - for(size_t j = 0; j < num_triangles; j++) { - Mesh::Triangle t = mesh->get_triangle(j); - float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]); - float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]); - float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]); - - surface_area += triangle_area(p1, p2, p3); - } - } - - kobject.tfm = tfm; - kobject.itfm = itfm; - kobject.surface_area = surface_area; - kobject.pass_id = pass_id; - kobject.random_number = random_number; - kobject.particle_index = particle_index; - kobject.motion_offset = 0; - - if(mesh->use_motion_blur) { - state->have_motion = true; - } - if(mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { - flag |= SD_OBJECT_HAS_VERTEX_MOTION; - } - - if(state->need_motion == Scene::MOTION_PASS) { - /* Clear motion array if there is no actual motion. */ - ob->update_motion(); - - /* Compute motion transforms. */ - Transform tfm_pre, tfm_post; - if(ob->use_motion()) { - tfm_pre = ob->motion[0]; - tfm_post = ob->motion[ob->motion.size() - 1]; - } - else { - tfm_pre = tfm; - tfm_post = tfm; - } - - /* Motion transformations, is world/object space depending if mesh - * comes with deformed position in object space, or if we transform - * the shading point in world space. */ - if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { - tfm_pre = tfm_pre * itfm; - tfm_post = tfm_post * itfm; - } - - int motion_pass_offset = ob->index*OBJECT_MOTION_PASS_SIZE; - object_motion_pass[motion_pass_offset + 0] = tfm_pre; - object_motion_pass[motion_pass_offset + 1] = tfm_post; - } - else if(state->need_motion == Scene::MOTION_BLUR) { - if(ob->use_motion()) { - kobject.motion_offset = state->motion_offset[ob->index]; - - /* Decompose transforms for interpolation. */ - DecomposedTransform *decomp = state->object_motion + kobject.motion_offset; - transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size()); - flag |= SD_OBJECT_MOTION; - state->have_motion = true; - } - } - - /* Dupli object coords and motion info. */ - kobject.dupli_generated[0] = ob->dupli_generated[0]; - kobject.dupli_generated[1] = ob->dupli_generated[1]; - kobject.dupli_generated[2] = ob->dupli_generated[2]; - kobject.numkeys = mesh->curve_keys.size(); - kobject.dupli_uv[0] = ob->dupli_uv[0]; - kobject.dupli_uv[1] = ob->dupli_uv[1]; - int totalsteps = mesh->motion_steps; - kobject.numsteps = (totalsteps - 1)/2; - kobject.numverts = mesh->verts.size(); - kobject.patch_map_offset = 0; - kobject.attribute_map_offset = 0; - uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); - uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); - kobject.cryptomatte_object = util_hash_to_float(hash_name); - kobject.cryptomatte_asset = util_hash_to_float(hash_asset); - - /* Object flag. */ - if(ob->use_holdout) { - flag |= SD_OBJECT_HOLDOUT_MASK; - } - state->object_flag[ob->index] = flag; - - /* Have curves. */ - if(mesh->num_curves()) { - state->have_curves = true; - } + KernelObject &kobject = state->objects[ob->index]; + Transform *object_motion_pass = state->object_motion_pass; + + Mesh *mesh = ob->mesh; + uint flag = 0; + + /* Compute transformations. */ + Transform tfm = ob->tfm; + Transform itfm = transform_inverse(tfm); + + /* Compute surface area. for uniform scale we can do avoid the many + * transform calls and share computation for instances. + * + * TODO(brecht): Correct for displacement, and move to a better place. + */ + float uniform_scale; + float surface_area = 0.0f; + float pass_id = ob->pass_id; + float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF); + int particle_index = (ob->particle_system) ? + ob->particle_index + state->particle_offset[ob->particle_system] : + 0; + + if (transform_uniform_scale(tfm, uniform_scale)) { + map<Mesh *, float>::iterator it; + + /* NOTE: This isn't fully optimal and could in theory lead to multiple + * threads calculating area of the same mesh in parallel. However, this + * also prevents suspending all the threads when some mesh's area is + * not yet known. + */ + state->surface_area_lock.lock(); + it = state->surface_area_map.find(mesh); + state->surface_area_lock.unlock(); + + if (it == state->surface_area_map.end()) { + size_t num_triangles = mesh->num_triangles(); + for (size_t j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); + float3 p1 = mesh->verts[t.v[0]]; + float3 p2 = mesh->verts[t.v[1]]; + float3 p3 = mesh->verts[t.v[2]]; + + surface_area += triangle_area(p1, p2, p3); + } + + state->surface_area_lock.lock(); + state->surface_area_map[mesh] = surface_area; + state->surface_area_lock.unlock(); + } + else { + surface_area = it->second; + } + + surface_area *= uniform_scale; + } + else { + size_t num_triangles = mesh->num_triangles(); + for (size_t j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); + float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]); + float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]); + float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]); + + surface_area += triangle_area(p1, p2, p3); + } + } + + kobject.tfm = tfm; + kobject.itfm = itfm; + kobject.surface_area = surface_area; + kobject.pass_id = pass_id; + kobject.random_number = random_number; + kobject.particle_index = particle_index; + kobject.motion_offset = 0; + + if (mesh->use_motion_blur) { + state->have_motion = true; + } + if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { + flag |= SD_OBJECT_HAS_VERTEX_MOTION; + } + + if (state->need_motion == Scene::MOTION_PASS) { + /* Clear motion array if there is no actual motion. */ + ob->update_motion(); + + /* Compute motion transforms. */ + Transform tfm_pre, tfm_post; + if (ob->use_motion()) { + tfm_pre = ob->motion[0]; + tfm_post = ob->motion[ob->motion.size() - 1]; + } + else { + tfm_pre = tfm; + tfm_post = tfm; + } + + /* Motion transformations, is world/object space depending if mesh + * comes with deformed position in object space, or if we transform + * the shading point in world space. */ + if (!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { + tfm_pre = tfm_pre * itfm; + tfm_post = tfm_post * itfm; + } + + int motion_pass_offset = ob->index * OBJECT_MOTION_PASS_SIZE; + object_motion_pass[motion_pass_offset + 0] = tfm_pre; + object_motion_pass[motion_pass_offset + 1] = tfm_post; + } + else if (state->need_motion == Scene::MOTION_BLUR) { + if (ob->use_motion()) { + kobject.motion_offset = state->motion_offset[ob->index]; + + /* Decompose transforms for interpolation. */ + DecomposedTransform *decomp = state->object_motion + kobject.motion_offset; + transform_motion_decompose(decomp, ob->motion.data(), ob->motion.size()); + flag |= SD_OBJECT_MOTION; + state->have_motion = true; + } + } + + /* Dupli object coords and motion info. */ + kobject.dupli_generated[0] = ob->dupli_generated[0]; + kobject.dupli_generated[1] = ob->dupli_generated[1]; + kobject.dupli_generated[2] = ob->dupli_generated[2]; + kobject.numkeys = mesh->curve_keys.size(); + kobject.dupli_uv[0] = ob->dupli_uv[0]; + kobject.dupli_uv[1] = ob->dupli_uv[1]; + int totalsteps = mesh->motion_steps; + kobject.numsteps = (totalsteps - 1) / 2; + kobject.numverts = mesh->verts.size(); + kobject.patch_map_offset = 0; + kobject.attribute_map_offset = 0; + uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); + uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); + kobject.cryptomatte_object = util_hash_to_float(hash_name); + kobject.cryptomatte_asset = util_hash_to_float(hash_asset); + + /* Object flag. */ + if (ob->use_holdout) { + flag |= SD_OBJECT_HOLDOUT_MASK; + } + state->object_flag[ob->index] = flag; + + /* Have curves. */ + if (mesh->num_curves()) { + state->have_curves = true; + } } -bool ObjectManager::device_update_object_transform_pop_work( - UpdateObjectTransformState *state, - int *start_index, - int *num_objects) +bool ObjectManager::device_update_object_transform_pop_work(UpdateObjectTransformState *state, + int *start_index, + int *num_objects) { - /* Tweakable parameter, number of objects per chunk. - * Too small value will cause some extra overhead due to spin lock, - * too big value might not use all threads nicely. - */ - static const int OBJECTS_PER_TASK = 32; - bool have_work = false; - state->queue_lock.lock(); - int num_scene_objects = state->scene->objects.size(); - if(state->queue_start_object < num_scene_objects) { - int count = min(OBJECTS_PER_TASK, - num_scene_objects - state->queue_start_object); - *start_index = state->queue_start_object; - *num_objects = count; - state->queue_start_object += count; - have_work = true; - } - state->queue_lock.unlock(); - return have_work; + /* Tweakable parameter, number of objects per chunk. + * Too small value will cause some extra overhead due to spin lock, + * too big value might not use all threads nicely. + */ + static const int OBJECTS_PER_TASK = 32; + bool have_work = false; + state->queue_lock.lock(); + int num_scene_objects = state->scene->objects.size(); + if (state->queue_start_object < num_scene_objects) { + int count = min(OBJECTS_PER_TASK, num_scene_objects - state->queue_start_object); + *start_index = state->queue_start_object; + *num_objects = count; + state->queue_start_object += count; + have_work = true; + } + state->queue_lock.unlock(); + return have_work; } -void ObjectManager::device_update_object_transform_task( - UpdateObjectTransformState *state) +void ObjectManager::device_update_object_transform_task(UpdateObjectTransformState *state) { - int start_index, num_objects; - while(device_update_object_transform_pop_work(state, - &start_index, - &num_objects)) - { - for(int i = 0; i < num_objects; ++i) { - const int object_index = start_index + i; - Object *ob = state->scene->objects[object_index]; - device_update_object_transform(state, ob); - } - } + int start_index, num_objects; + while (device_update_object_transform_pop_work(state, &start_index, &num_objects)) { + for (int i = 0; i < num_objects; ++i) { + const int object_index = start_index + i; + Object *ob = state->scene->objects[object_index]; + device_update_object_transform(state, ob); + } + } } -void ObjectManager::device_update_transforms(DeviceScene *dscene, - Scene *scene, - Progress& progress) +void ObjectManager::device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) { - UpdateObjectTransformState state; - state.need_motion = scene->need_motion(); - state.have_motion = false; - state.have_curves = false; - state.scene = scene; - state.queue_start_object = 0; - - state.objects = dscene->objects.alloc(scene->objects.size()); - state.object_flag = dscene->object_flag.alloc(scene->objects.size()); - state.object_motion = NULL; - state.object_motion_pass = NULL; - - if(state.need_motion == Scene::MOTION_PASS) { - state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE*scene->objects.size()); - } - else if(state.need_motion == Scene::MOTION_BLUR) { - /* Set object offsets into global object motion array. */ - uint *motion_offsets = state.motion_offset.resize(scene->objects.size()); - uint motion_offset = 0; - - foreach(Object *ob, scene->objects) { - *motion_offsets = motion_offset; - motion_offsets++; - - /* Clear motion array if there is no actual motion. */ - ob->update_motion(); - motion_offset += ob->motion.size(); - } - - state.object_motion = dscene->object_motion.alloc(motion_offset); - } - - /* Particle system device offsets - * 0 is dummy particle, index starts at 1. - */ - int numparticles = 1; - foreach(ParticleSystem *psys, scene->particle_systems) { - state.particle_offset[psys] = numparticles; - numparticles += psys->particles.size(); - } - - /* NOTE: If it's just a handful of objects we deal with them in a single - * thread to avoid threading overhead. However, this threshold is might - * need some tweaks to make mid-complex scenes optimal. - */ - if(scene->objects.size() < 64) { - foreach(Object *ob, scene->objects) { - device_update_object_transform(&state, ob); - if(progress.get_cancel()) { - return; - } - } - } - else { - const int num_threads = TaskScheduler::num_threads(); - TaskPool pool; - for(int i = 0; i < num_threads; ++i) { - pool.push(function_bind( - &ObjectManager::device_update_object_transform_task, - this, - &state)); - } - pool.wait_work(); - if(progress.get_cancel()) { - return; - } - } - - dscene->objects.copy_to_device(); - if(state.need_motion == Scene::MOTION_PASS) { - dscene->object_motion_pass.copy_to_device(); - } - else if(state.need_motion == Scene::MOTION_BLUR) { - dscene->object_motion.copy_to_device(); - } - - dscene->data.bvh.have_motion = state.have_motion; - dscene->data.bvh.have_curves = state.have_curves; - dscene->data.bvh.have_instancing = true; + UpdateObjectTransformState state; + state.need_motion = scene->need_motion(); + state.have_motion = false; + state.have_curves = false; + state.scene = scene; + state.queue_start_object = 0; + + state.objects = dscene->objects.alloc(scene->objects.size()); + state.object_flag = dscene->object_flag.alloc(scene->objects.size()); + state.object_motion = NULL; + state.object_motion_pass = NULL; + + if (state.need_motion == Scene::MOTION_PASS) { + state.object_motion_pass = dscene->object_motion_pass.alloc(OBJECT_MOTION_PASS_SIZE * + scene->objects.size()); + } + else if (state.need_motion == Scene::MOTION_BLUR) { + /* Set object offsets into global object motion array. */ + uint *motion_offsets = state.motion_offset.resize(scene->objects.size()); + uint motion_offset = 0; + + foreach (Object *ob, scene->objects) { + *motion_offsets = motion_offset; + motion_offsets++; + + /* Clear motion array if there is no actual motion. */ + ob->update_motion(); + motion_offset += ob->motion.size(); + } + + state.object_motion = dscene->object_motion.alloc(motion_offset); + } + + /* Particle system device offsets + * 0 is dummy particle, index starts at 1. + */ + int numparticles = 1; + foreach (ParticleSystem *psys, scene->particle_systems) { + state.particle_offset[psys] = numparticles; + numparticles += psys->particles.size(); + } + + /* NOTE: If it's just a handful of objects we deal with them in a single + * thread to avoid threading overhead. However, this threshold is might + * need some tweaks to make mid-complex scenes optimal. + */ + if (scene->objects.size() < 64) { + foreach (Object *ob, scene->objects) { + device_update_object_transform(&state, ob); + if (progress.get_cancel()) { + return; + } + } + } + else { + const int num_threads = TaskScheduler::num_threads(); + TaskPool pool; + for (int i = 0; i < num_threads; ++i) { + pool.push(function_bind(&ObjectManager::device_update_object_transform_task, this, &state)); + } + pool.wait_work(); + if (progress.get_cancel()) { + return; + } + } + + dscene->objects.copy_to_device(); + if (state.need_motion == Scene::MOTION_PASS) { + dscene->object_motion_pass.copy_to_device(); + } + else if (state.need_motion == Scene::MOTION_BLUR) { + dscene->object_motion.copy_to_device(); + } + + dscene->data.bvh.have_motion = state.have_motion; + dscene->data.bvh.have_curves = state.have_curves; + dscene->data.bvh.have_instancing = true; } -void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void ObjectManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - VLOG(1) << "Total " << scene->objects.size() << " objects."; + VLOG(1) << "Total " << scene->objects.size() << " objects."; - device_free(device, dscene); + device_free(device, dscene); - if(scene->objects.size() == 0) - return; + if (scene->objects.size() == 0) + return; - /* Assign object IDs. */ - int index = 0; - foreach(Object *object, scene->objects) { - object->index = index++; - } + /* Assign object IDs. */ + int index = 0; + foreach (Object *object, scene->objects) { + object->index = index++; + } - /* set object transform matrices, before applying static transforms */ - progress.set_status("Updating Objects", "Copying Transformations to device"); - device_update_transforms(dscene, scene, progress); + /* set object transform matrices, before applying static transforms */ + progress.set_status("Updating Objects", "Copying Transformations to device"); + device_update_transforms(dscene, scene, progress); - if(progress.get_cancel()) return; + if (progress.get_cancel()) + return; - /* prepare for static BVH building */ - /* todo: do before to support getting object level coords? */ - if(scene->params.bvh_type == SceneParams::BVH_STATIC) { - progress.set_status("Updating Objects", "Applying Static Transformations"); - apply_static_transforms(dscene, scene, progress); - } + /* prepare for static BVH building */ + /* todo: do before to support getting object level coords? */ + if (scene->params.bvh_type == SceneParams::BVH_STATIC) { + progress.set_status("Updating Objects", "Applying Static Transformations"); + apply_static_transforms(dscene, scene, progress); + } } -void ObjectManager::device_update_flags(Device *, - DeviceScene *dscene, - Scene *scene, - Progress& /*progress*/, - bool bounds_valid) +void ObjectManager::device_update_flags( + Device *, DeviceScene *dscene, Scene *scene, Progress & /*progress*/, bool bounds_valid) { - if(!need_update && !need_flags_update) - return; - - need_update = false; - need_flags_update = false; - - if(scene->objects.size() == 0) - return; - - /* Object info flag. */ - uint *object_flag = dscene->object_flag.data(); - - /* Object volume intersection. */ - vector<Object *> volume_objects; - bool has_volume_objects = false; - foreach(Object *object, scene->objects) { - if(object->mesh->has_volume) { - if(bounds_valid) { - volume_objects.push_back(object); - } - has_volume_objects = true; - } - } - - foreach(Object *object, scene->objects) { - if(object->mesh->has_volume) { - object_flag[object->index] |= SD_OBJECT_HAS_VOLUME; - object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES; - - foreach(Attribute& attr, object->mesh->attributes.attributes) { - if(attr.element == ATTR_ELEMENT_VOXEL) { - object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES; - } - } - } - else { - object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME|SD_OBJECT_HAS_VOLUME_ATTRIBUTES); - } - if(object->is_shadow_catcher) { - object_flag[object->index] |= SD_OBJECT_SHADOW_CATCHER; - } - else { - object_flag[object->index] &= ~SD_OBJECT_SHADOW_CATCHER; - } - - if(bounds_valid) { - foreach(Object *volume_object, volume_objects) { - if(object == volume_object) { - continue; - } - if(object->bounds.intersects(volume_object->bounds)) { - object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME; - break; - } - } - } - else if(has_volume_objects) { - /* Not really valid, but can't make more reliable in the case - * of bounds not being up to date. - */ - object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME; - } - } - - /* Copy object flag. */ - dscene->object_flag.copy_to_device(); + if (!need_update && !need_flags_update) + return; + + need_update = false; + need_flags_update = false; + + if (scene->objects.size() == 0) + return; + + /* Object info flag. */ + uint *object_flag = dscene->object_flag.data(); + + /* Object volume intersection. */ + vector<Object *> volume_objects; + bool has_volume_objects = false; + foreach (Object *object, scene->objects) { + if (object->mesh->has_volume) { + if (bounds_valid) { + volume_objects.push_back(object); + } + has_volume_objects = true; + } + } + + foreach (Object *object, scene->objects) { + if (object->mesh->has_volume) { + object_flag[object->index] |= SD_OBJECT_HAS_VOLUME; + object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES; + + foreach (Attribute &attr, object->mesh->attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES; + } + } + } + else { + object_flag[object->index] &= ~(SD_OBJECT_HAS_VOLUME | SD_OBJECT_HAS_VOLUME_ATTRIBUTES); + } + if (object->is_shadow_catcher) { + object_flag[object->index] |= SD_OBJECT_SHADOW_CATCHER; + } + else { + object_flag[object->index] &= ~SD_OBJECT_SHADOW_CATCHER; + } + + if (bounds_valid) { + foreach (Object *volume_object, volume_objects) { + if (object == volume_object) { + continue; + } + if (object->bounds.intersects(volume_object->bounds)) { + object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME; + break; + } + } + } + else if (has_volume_objects) { + /* Not really valid, but can't make more reliable in the case + * of bounds not being up to date. + */ + object_flag[object->index] |= SD_OBJECT_INTERSECTS_VOLUME; + } + } + + /* Copy object flag. */ + dscene->object_flag.copy_to_device(); } void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene) { - if(dscene->objects.size() == 0) { - return; - } + if (dscene->objects.size() == 0) { + return; + } - KernelObject *kobjects = dscene->objects.data(); + KernelObject *kobjects = dscene->objects.data(); - bool update = false; + bool update = false; - foreach(Object *object, scene->objects) { - Mesh* mesh = object->mesh; + foreach (Object *object, scene->objects) { + Mesh *mesh = object->mesh; - if(mesh->patch_table) { - uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() - - mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset; + if (mesh->patch_table) { + uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() - + mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - + mesh->patch_offset; - if(kobjects[object->index].patch_map_offset != patch_map_offset) { - kobjects[object->index].patch_map_offset = patch_map_offset; - update = true; - } - } + if (kobjects[object->index].patch_map_offset != patch_map_offset) { + kobjects[object->index].patch_map_offset = patch_map_offset; + update = true; + } + } - if(kobjects[object->index].attribute_map_offset != mesh->attr_map_offset) { - kobjects[object->index].attribute_map_offset = mesh->attr_map_offset; - update = true; - } - } + if (kobjects[object->index].attribute_map_offset != mesh->attr_map_offset) { + kobjects[object->index].attribute_map_offset = mesh->attr_map_offset; + update = true; + } + } - if(update) { - dscene->objects.copy_to_device(); - } + if (update) { + dscene->objects.copy_to_device(); + } } void ObjectManager::device_free(Device *, DeviceScene *dscene) { - dscene->objects.free(); - dscene->object_motion_pass.free(); - dscene->object_motion.free(); - dscene->object_flag.free(); + dscene->objects.free(); + dscene->object_motion_pass.free(); + dscene->object_motion.free(); + dscene->object_flag.free(); } -void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress) +void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) { - /* todo: normals and displacement should be done before applying transform! */ - /* todo: create objects/meshes in right order! */ - - /* counter mesh users */ - map<Mesh*, int> mesh_users; - Scene::MotionType need_motion = scene->need_motion(); - bool motion_blur = need_motion == Scene::MOTION_BLUR; - bool apply_to_motion = need_motion != Scene::MOTION_PASS; - int i = 0; - bool have_instancing = false; - - foreach(Object *object, scene->objects) { - map<Mesh*, int>::iterator it = mesh_users.find(object->mesh); - - if(it == mesh_users.end()) - mesh_users[object->mesh] = 1; - else - it->second++; - } - - if(progress.get_cancel()) return; - - uint *object_flag = dscene->object_flag.data(); - - /* apply transforms for objects with single user meshes */ - foreach(Object *object, scene->objects) { - /* Annoying feedback loop here: we can't use is_instanced() because - * it'll use uninitialized transform_applied flag. - * - * Could be solved by moving reference counter to Mesh. - */ - if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) && - !object->mesh->has_true_displacement() && object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE) - { - if(!(motion_blur && object->use_motion())) { - if(!object->mesh->transform_applied) { - object->apply_transform(apply_to_motion); - object->mesh->transform_applied = true; - - if(progress.get_cancel()) return; - } - - object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; - if(object->mesh->transform_negative_scaled) - object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; - } - else - have_instancing = true; - } - else - have_instancing = true; - - i++; - } - - dscene->data.bvh.have_instancing = have_instancing; + /* todo: normals and displacement should be done before applying transform! */ + /* todo: create objects/meshes in right order! */ + + /* counter mesh users */ + map<Mesh *, int> mesh_users; + Scene::MotionType need_motion = scene->need_motion(); + bool motion_blur = need_motion == Scene::MOTION_BLUR; + bool apply_to_motion = need_motion != Scene::MOTION_PASS; + int i = 0; + bool have_instancing = false; + + foreach (Object *object, scene->objects) { + map<Mesh *, int>::iterator it = mesh_users.find(object->mesh); + + if (it == mesh_users.end()) + mesh_users[object->mesh] = 1; + else + it->second++; + } + + if (progress.get_cancel()) + return; + + uint *object_flag = dscene->object_flag.data(); + + /* apply transforms for objects with single user meshes */ + foreach (Object *object, scene->objects) { + /* Annoying feedback loop here: we can't use is_instanced() because + * it'll use uninitialized transform_applied flag. + * + * Could be solved by moving reference counter to Mesh. + */ + if ((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) && + !object->mesh->has_true_displacement() && + object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { + if (!(motion_blur && object->use_motion())) { + if (!object->mesh->transform_applied) { + object->apply_transform(apply_to_motion); + object->mesh->transform_applied = true; + + if (progress.get_cancel()) + return; + } + + object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; + if (object->mesh->transform_negative_scaled) + object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; + } + else + have_instancing = true; + } + else + have_instancing = true; + + i++; + } + + dscene->data.bvh.have_instancing = have_instancing; } void ObjectManager::tag_update(Scene *scene) { - need_update = true; - scene->curve_system_manager->need_update = true; - scene->mesh_manager->need_update = true; - scene->light_manager->need_update = true; + need_update = true; + scene->curve_system_manager->need_update = true; + scene->mesh_manager->need_update = true; + scene->light_manager->need_update = true; } string ObjectManager::get_cryptomatte_objects(Scene *scene) { - string manifest = "{"; - - unordered_set<ustring, ustringHash> objects; - foreach(Object *object, scene->objects) { - if(objects.count(object->name)) { - continue; - } - objects.insert(object->name); - uint32_t hash_name = util_murmur_hash3(object->name.c_str(), object->name.length(), 0); - manifest += string_printf("\"%s\":\"%08x\",", object->name.c_str(), hash_name); - } - manifest[manifest.size()-1] = '}'; - return manifest; + string manifest = "{"; + + unordered_set<ustring, ustringHash> objects; + foreach (Object *object, scene->objects) { + if (objects.count(object->name)) { + continue; + } + objects.insert(object->name); + uint32_t hash_name = util_murmur_hash3(object->name.c_str(), object->name.length(), 0); + manifest += string_printf("\"%s\":\"%08x\",", object->name.c_str(), hash_name); + } + manifest[manifest.size() - 1] = '}'; + return manifest; } string ObjectManager::get_cryptomatte_assets(Scene *scene) { - string manifest = "{"; - unordered_set<ustring, ustringHash> assets; - foreach(Object *ob, scene->objects) { - if(assets.count(ob->asset_name)) { - continue; - } - assets.insert(ob->asset_name); - uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); - manifest += string_printf("\"%s\":\"%08x\",", ob->asset_name.c_str(), hash_asset); - } - manifest[manifest.size()-1] = '}'; - return manifest; + string manifest = "{"; + unordered_set<ustring, ustringHash> assets; + foreach (Object *ob, scene->objects) { + if (assets.count(ob->asset_name)) { + continue; + } + assets.insert(ob->asset_name); + uint32_t hash_asset = util_murmur_hash3(ob->asset_name.c_str(), ob->asset_name.length(), 0); + manifest += string_printf("\"%s\":\"%08x\",", ob->asset_name.c_str(), hash_asset); + } + manifest[manifest.size() - 1] = '}'; + return manifest; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 134f0bc3577..2fd43900da1 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -43,105 +43,101 @@ class ObjectManager; /* Object */ class Object : public Node { -public: - NODE_DECLARE - - Mesh *mesh; - Transform tfm; - BoundBox bounds; - uint random_id; - int pass_id; - ustring asset_name; - vector<ParamValue> attributes; - uint visibility; - array<Transform> motion; - bool hide_on_missing_motion; - bool use_holdout; - bool is_shadow_catcher; - - float3 dupli_generated; - float2 dupli_uv; - - ParticleSystem *particle_system; - int particle_index; - - Object(); - ~Object(); - - void tag_update(Scene *scene); - - void compute_bounds(bool motion_blur); - void apply_transform(bool apply_to_motion); - - /* Convert between normalized -1..1 motion time and index - * in the motion array. */ - bool use_motion() const; - float motion_time(int step) const; - int motion_step(float time) const; - void update_motion(); - - /* Check whether object is traceable and it worth adding it to - * kernel scene. - */ - bool is_traceable() const; - - /* Combine object's visibility with all possible internal run-time - * determined flags which denotes trace-time visibility. - */ - uint visibility_for_tracing() const; - - /* Returns the index that is used in the kernel for this object. */ - int get_device_index() const; - -protected: - /* Specifies the position of the object in scene->objects and - * in the device vectors. Gets set in device_update. */ - int index; - - friend class ObjectManager; + public: + NODE_DECLARE + + Mesh *mesh; + Transform tfm; + BoundBox bounds; + uint random_id; + int pass_id; + ustring asset_name; + vector<ParamValue> attributes; + uint visibility; + array<Transform> motion; + bool hide_on_missing_motion; + bool use_holdout; + bool is_shadow_catcher; + + float3 dupli_generated; + float2 dupli_uv; + + ParticleSystem *particle_system; + int particle_index; + + Object(); + ~Object(); + + void tag_update(Scene *scene); + + void compute_bounds(bool motion_blur); + void apply_transform(bool apply_to_motion); + + /* Convert between normalized -1..1 motion time and index + * in the motion array. */ + bool use_motion() const; + float motion_time(int step) const; + int motion_step(float time) const; + void update_motion(); + + /* Check whether object is traceable and it worth adding it to + * kernel scene. + */ + bool is_traceable() const; + + /* Combine object's visibility with all possible internal run-time + * determined flags which denotes trace-time visibility. + */ + uint visibility_for_tracing() const; + + /* Returns the index that is used in the kernel for this object. */ + int get_device_index() const; + + protected: + /* Specifies the position of the object in scene->objects and + * in the device vectors. Gets set in device_update. */ + int index; + + friend class ObjectManager; }; /* Object Manager */ class ObjectManager { -public: - bool need_update; - bool need_flags_update; - - ObjectManager(); - ~ObjectManager(); - - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_transforms(DeviceScene *dscene, - Scene *scene, - Progress& progress); - - void device_update_flags(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress& progress, - bool bounds_valid = true); - void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene); - - void device_free(Device *device, DeviceScene *dscene); - - void tag_update(Scene *scene); - - void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress& progress); - - string get_cryptomatte_objects(Scene *scene); - string get_cryptomatte_assets(Scene *scene); - -protected: - void device_update_object_transform(UpdateObjectTransformState *state, - Object *ob); - void device_update_object_transform_task(UpdateObjectTransformState *state); - bool device_update_object_transform_pop_work( - UpdateObjectTransformState *state, - int *start_index, - int *num_objects); + public: + bool need_update; + bool need_flags_update; + + ObjectManager(); + ~ObjectManager(); + + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_update_transforms(DeviceScene *dscene, Scene *scene, Progress &progress); + + void device_update_flags(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress, + bool bounds_valid = true); + void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene); + + void device_free(Device *device, DeviceScene *dscene); + + void tag_update(Scene *scene); + + void apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress); + + string get_cryptomatte_objects(Scene *scene); + string get_cryptomatte_assets(Scene *scene); + + protected: + void device_update_object_transform(UpdateObjectTransformState *state, Object *ob); + void device_update_object_transform_task(UpdateObjectTransformState *state); + bool device_update_object_transform_pop_work(UpdateObjectTransformState *state, + int *start_index, + int *num_objects); }; CCL_NAMESPACE_END -#endif /* __OBJECT_H__ */ +#endif /* __OBJECT_H__ */ diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index c603dc69a16..b66a46938be 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -25,16 +25,16 @@ #ifdef WITH_OSL -#include "kernel/osl/osl_globals.h" -#include "kernel/osl/osl_services.h" -#include "kernel/osl/osl_shader.h" +# include "kernel/osl/osl_globals.h" +# include "kernel/osl/osl_services.h" +# include "kernel/osl/osl_shader.h" -#include "util/util_foreach.h" -#include "util/util_logging.h" -#include "util/util_md5.h" -#include "util/util_path.h" -#include "util/util_progress.h" -#include "util/util_projection.h" +# include "util/util_foreach.h" +# include "util/util_logging.h" +# include "util/util_md5.h" +# include "util/util_path.h" +# include "util/util_progress.h" +# include "util/util_projection.h" #endif @@ -58,1151 +58,1140 @@ thread_mutex OSLShaderManager::ss_mutex; OSLShaderManager::OSLShaderManager() { - texture_system_init(); - shading_system_init(); + texture_system_init(); + shading_system_init(); } OSLShaderManager::~OSLShaderManager() { - shading_system_free(); - texture_system_free(); + shading_system_free(); + texture_system_free(); } void OSLShaderManager::free_memory() { -#ifdef OSL_HAS_BLENDER_CLEANUP_FIX - /* There is a problem with llvm+osl: The order global destructors across - * different compilation units run cannot be guaranteed, on windows this means - * that the llvm destructors run before the osl destructors, causing a crash - * when the process exits. the OSL in svn has a special cleanup hack to - * sidestep this behavior */ - OSL::pvt::LLVM_Util::Cleanup(); -#endif +# ifdef OSL_HAS_BLENDER_CLEANUP_FIX + /* There is a problem with llvm+osl: The order global destructors across + * different compilation units run cannot be guaranteed, on windows this means + * that the llvm destructors run before the osl destructors, causing a crash + * when the process exits. the OSL in svn has a special cleanup hack to + * sidestep this behavior */ + OSL::pvt::LLVM_Util::Cleanup(); +# endif } void OSLShaderManager::reset(Scene * /*scene*/) { - shading_system_free(); - shading_system_init(); + shading_system_free(); + shading_system_init(); } -void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void OSLShaderManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - VLOG(1) << "Total " << scene->shaders.size() << " shaders."; + VLOG(1) << "Total " << scene->shaders.size() << " shaders."; - device_free(device, dscene, scene); + device_free(device, dscene, scene); - /* determine which shaders are in use */ - device_update_shaders_used(scene); + /* determine which shaders are in use */ + device_update_shaders_used(scene); - /* create shaders */ - OSLGlobals *og = (OSLGlobals*)device->osl_memory(); + /* create shaders */ + OSLGlobals *og = (OSLGlobals *)device->osl_memory(); - foreach(Shader *shader, scene->shaders) { - assert(shader->graph); + foreach (Shader *shader, scene->shaders) { + assert(shader->graph); - if(progress.get_cancel()) return; + if (progress.get_cancel()) + return; - /* we can only compile one shader at the time as the OSL ShadingSytem - * has a single state, but we put the lock here so different renders can - * compile shaders alternating */ - thread_scoped_lock lock(ss_mutex); + /* we can only compile one shader at the time as the OSL ShadingSytem + * has a single state, but we put the lock here so different renders can + * compile shaders alternating */ + thread_scoped_lock lock(ss_mutex); - OSLCompiler compiler((void*)this, (void*)ss, - scene->image_manager, - scene->light_manager); - compiler.background = (shader == scene->default_background); - compiler.compile(scene, og, shader); + OSLCompiler compiler((void *)this, (void *)ss, scene->image_manager, scene->light_manager); + compiler.background = (shader == scene->default_background); + compiler.compile(scene, og, shader); - if(shader->use_mis && shader->has_surface_emission) - scene->light_manager->need_update = true; - } + if (shader->use_mis && shader->has_surface_emission) + scene->light_manager->need_update = true; + } - /* setup shader engine */ - og->ss = ss; - og->ts = ts; - og->services = services; + /* setup shader engine */ + og->ss = ss; + og->ts = ts; + og->services = services; - int background_id = scene->shader_manager->get_shader_id(scene->default_background); - og->background_state = og->surface_state[background_id & SHADER_MASK]; - og->use = true; + int background_id = scene->shader_manager->get_shader_id(scene->default_background); + og->background_state = og->surface_state[background_id & SHADER_MASK]; + og->use = true; - foreach(Shader *shader, scene->shaders) - shader->need_update = false; + foreach (Shader *shader, scene->shaders) + shader->need_update = false; - need_update = false; + need_update = false; - /* set texture system */ - scene->image_manager->set_osl_texture_system((void*)ts); + /* set texture system */ + scene->image_manager->set_osl_texture_system((void *)ts); - device_update_common(device, dscene, scene, progress); + device_update_common(device, dscene, scene, progress); - { - /* Perform greedyjit optimization. - * - * This might waste time on optimizing gorups which are never actually - * used, but this prevents OSL from allocating data on TLS at render - * time. - * - * This is much better for us because this way we aren't required to - * stop task scheduler threads to make sure all TLS is clean and don't - * have issues with TLS data free accessing freed memory if task scheduler - * is being freed after the Session is freed. - */ - thread_scoped_lock lock(ss_shared_mutex); - ss->optimize_all_groups(); - } + { + /* Perform greedyjit optimization. + * + * This might waste time on optimizing gorups which are never actually + * used, but this prevents OSL from allocating data on TLS at render + * time. + * + * This is much better for us because this way we aren't required to + * stop task scheduler threads to make sure all TLS is clean and don't + * have issues with TLS data free accessing freed memory if task scheduler + * is being freed after the Session is freed. + */ + thread_scoped_lock lock(ss_shared_mutex); + ss->optimize_all_groups(); + } } 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, scene); + device_free_common(device, dscene, scene); - /* clear shader engine */ - og->use = false; - og->ss = NULL; - og->ts = NULL; + /* clear shader engine */ + og->use = false; + og->ss = NULL; + og->ts = NULL; - og->surface_state.clear(); - og->volume_state.clear(); - og->displacement_state.clear(); - og->bump_state.clear(); - og->background_state.reset(); + og->surface_state.clear(); + og->volume_state.clear(); + og->displacement_state.clear(); + og->bump_state.clear(); + og->background_state.reset(); } void OSLShaderManager::texture_system_init() { - /* create texture system, shared between different renders to reduce memory usage */ - thread_scoped_lock lock(ts_shared_mutex); + /* create texture system, shared between different renders to reduce memory usage */ + thread_scoped_lock lock(ts_shared_mutex); - if(ts_shared_users == 0) { - ts_shared = TextureSystem::create(true); + if (ts_shared_users == 0) { + ts_shared = TextureSystem::create(true); - ts_shared->attribute("automip", 1); - ts_shared->attribute("autotile", 64); - ts_shared->attribute("gray_to_rgb", 1); + ts_shared->attribute("automip", 1); + ts_shared->attribute("autotile", 64); + ts_shared->attribute("gray_to_rgb", 1); - /* effectively unlimited for now, until we support proper mipmap lookups */ - ts_shared->attribute("max_memory_MB", 16384); - } + /* effectively unlimited for now, until we support proper mipmap lookups */ + ts_shared->attribute("max_memory_MB", 16384); + } - ts = ts_shared; - ts_shared_users++; + ts = ts_shared; + ts_shared_users++; } void OSLShaderManager::texture_system_free() { - /* shared texture system decrease users and destroy if no longer used */ - thread_scoped_lock lock(ts_shared_mutex); - ts_shared_users--; + /* shared texture system decrease users and destroy if no longer used */ + thread_scoped_lock lock(ts_shared_mutex); + ts_shared_users--; - if(ts_shared_users == 0) { - ts_shared->invalidate_all(true); - OSL::TextureSystem::destroy(ts_shared); - ts_shared = NULL; - } + if (ts_shared_users == 0) { + ts_shared->invalidate_all(true); + OSL::TextureSystem::destroy(ts_shared); + ts_shared = NULL; + } - ts = NULL; + ts = NULL; } void OSLShaderManager::shading_system_init() { - /* create shading system, shared between different renders to reduce memory usage */ - thread_scoped_lock lock(ss_shared_mutex); - - if(ss_shared_users == 0) { - services_shared = new OSLRenderServices(); - - string shader_path = path_get("shader"); -#ifdef _WIN32 - /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can - * operate with file paths with any character. This requires to use wide - * char functions, but OSL uses old fashioned ANSI functions which means: - * - * - We have to convert our paths to ANSI before passing to OSL - * - OSL can't be used when there's a multi-byte character in the path - * to the shaders folder. - */ - shader_path = string_to_ansi(shader_path); -#endif - - ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler); - ss_shared->attribute("lockgeom", 1); - ss_shared->attribute("commonspace", "world"); - ss_shared->attribute("searchpath:shader", shader_path); - ss_shared->attribute("greedyjit", 1); - - VLOG(1) << "Using shader search path: " << shader_path; - - /* our own ray types */ - static const char *raytypes[] = { - "camera", /* PATH_RAY_CAMERA */ - "reflection", /* PATH_RAY_REFLECT */ - "refraction", /* PATH_RAY_TRANSMIT */ - "diffuse", /* PATH_RAY_DIFFUSE */ - "glossy", /* PATH_RAY_GLOSSY */ - "singular", /* PATH_RAY_SINGULAR */ - "transparent", /* PATH_RAY_TRANSPARENT */ - - "shadow", /* PATH_RAY_SHADOW_OPAQUE_NON_CATCHER */ - "shadow", /* PATH_RAY_SHADOW_OPAQUE_CATCHER */ - "shadow", /* PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER */ - "shadow", /* PATH_RAY_SHADOW_TRANSPARENT_CATCHER */ - - "__unused__", - "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */ - "__unused__", - - "__unused__", - "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */ - "__unused__", - "__unused__", - "__unused__", - "__unused__", - "__unused__", - "__unused__", - "__unused__", - }; - - const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]); - ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes); - - OSLShader::register_closures((OSLShadingSystem*)ss_shared); - - loaded_shaders.clear(); - } - - ss = ss_shared; - services = services_shared; - ss_shared_users++; + /* create shading system, shared between different renders to reduce memory usage */ + thread_scoped_lock lock(ss_shared_mutex); + + if (ss_shared_users == 0) { + services_shared = new OSLRenderServices(); + + string shader_path = path_get("shader"); +# ifdef _WIN32 + /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can + * operate with file paths with any character. This requires to use wide + * char functions, but OSL uses old fashioned ANSI functions which means: + * + * - We have to convert our paths to ANSI before passing to OSL + * - OSL can't be used when there's a multi-byte character in the path + * to the shaders folder. + */ + shader_path = string_to_ansi(shader_path); +# endif + + ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler); + ss_shared->attribute("lockgeom", 1); + ss_shared->attribute("commonspace", "world"); + ss_shared->attribute("searchpath:shader", shader_path); + ss_shared->attribute("greedyjit", 1); + + VLOG(1) << "Using shader search path: " << shader_path; + + /* our own ray types */ + static const char *raytypes[] = { + "camera", /* PATH_RAY_CAMERA */ + "reflection", /* PATH_RAY_REFLECT */ + "refraction", /* PATH_RAY_TRANSMIT */ + "diffuse", /* PATH_RAY_DIFFUSE */ + "glossy", /* PATH_RAY_GLOSSY */ + "singular", /* PATH_RAY_SINGULAR */ + "transparent", /* PATH_RAY_TRANSPARENT */ + + "shadow", /* PATH_RAY_SHADOW_OPAQUE_NON_CATCHER */ + "shadow", /* PATH_RAY_SHADOW_OPAQUE_CATCHER */ + "shadow", /* PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER */ + "shadow", /* PATH_RAY_SHADOW_TRANSPARENT_CATCHER */ + + "__unused__", "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */ + "__unused__", + + "__unused__", "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */ + "__unused__", "__unused__", "__unused__", "__unused__", + "__unused__", "__unused__", "__unused__", + }; + + const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]); + ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes); + + OSLShader::register_closures((OSLShadingSystem *)ss_shared); + + loaded_shaders.clear(); + } + + ss = ss_shared; + services = services_shared; + ss_shared_users++; } void OSLShaderManager::shading_system_free() { - /* shared shading system decrease users and destroy if no longer used */ - thread_scoped_lock lock(ss_shared_mutex); - ss_shared_users--; + /* shared shading system decrease users and destroy if no longer used */ + thread_scoped_lock lock(ss_shared_mutex); + ss_shared_users--; - if(ss_shared_users == 0) { - delete ss_shared; - ss_shared = NULL; + if (ss_shared_users == 0) { + delete ss_shared; + ss_shared = NULL; - delete services_shared; - services_shared = NULL; - } + delete services_shared; + services_shared = NULL; + } - ss = NULL; - services = NULL; + ss = NULL; + services = NULL; } -bool OSLShaderManager::osl_compile(const string& inputfile, const string& outputfile) +bool OSLShaderManager::osl_compile(const string &inputfile, const string &outputfile) { - vector<string> options; - string stdosl_path; - string shader_path = path_get("shader"); + vector<string> options; + string stdosl_path; + string shader_path = path_get("shader"); - /* specify output file name */ - options.push_back("-o"); - options.push_back(outputfile); + /* specify output file name */ + options.push_back("-o"); + options.push_back(outputfile); - /* specify standard include path */ - string include_path_arg = string("-I") + shader_path; - options.push_back(include_path_arg); + /* specify standard include path */ + string include_path_arg = string("-I") + shader_path; + options.push_back(include_path_arg); - stdosl_path = path_get("shader/stdosl.h"); + stdosl_path = path_get("shader/stdosl.h"); - /* compile */ - OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler()); - bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path)); - delete compiler; + /* compile */ + OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler()); + bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path)); + delete compiler; - return ok; + return ok; } -bool OSLShaderManager::osl_query(OSL::OSLQuery& query, const string& filepath) +bool OSLShaderManager::osl_query(OSL::OSLQuery &query, const string &filepath) { - string searchpath = path_user_get("shaders"); - return query.open(filepath, searchpath); + string searchpath = path_user_get("shaders"); + return query.open(filepath, searchpath); } -static string shader_filepath_hash(const string& filepath, uint64_t modified_time) +static string shader_filepath_hash(const string &filepath, uint64_t modified_time) { - /* compute a hash from filepath and modified time to detect changes */ - MD5Hash md5; - md5.append((const uint8_t*)filepath.c_str(), filepath.size()); - md5.append((const uint8_t*)&modified_time, sizeof(modified_time)); + /* compute a hash from filepath and modified time to detect changes */ + MD5Hash md5; + md5.append((const uint8_t *)filepath.c_str(), filepath.size()); + md5.append((const uint8_t *)&modified_time, sizeof(modified_time)); - return md5.get_hex(); + return md5.get_hex(); } -const char *OSLShaderManager::shader_test_loaded(const string& hash) +const char *OSLShaderManager::shader_test_loaded(const string &hash) { - map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash); - return (it == loaded_shaders.end())? NULL: it->first.c_str(); + map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash); + return (it == loaded_shaders.end()) ? NULL : it->first.c_str(); } -OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string& hash) +OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string &hash) { - map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash); - return (it == loaded_shaders.end())? NULL: &it->second; + map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash); + return (it == loaded_shaders.end()) ? NULL : &it->second; } const char *OSLShaderManager::shader_load_filepath(string filepath) { - size_t len = filepath.size(); - string extension = filepath.substr(len - 4); - uint64_t modified_time = path_modified_time(filepath); - - if(extension == ".osl") { - /* .OSL File */ - string osopath = filepath.substr(0, len - 4) + ".oso"; - uint64_t oso_modified_time = path_modified_time(osopath); - - /* test if we have loaded the corresponding .OSO already */ - if(oso_modified_time != 0) { - const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time)); - - if(hash) - return hash; - } - - /* autocompile .OSL to .OSO if needed */ - if(oso_modified_time == 0 || (oso_modified_time < modified_time)) { - OSLShaderManager::osl_compile(filepath, osopath); - modified_time = path_modified_time(osopath); - } - else - modified_time = oso_modified_time; - - filepath = osopath; - } - else { - if(extension == ".oso") { - /* .OSO File, nothing to do */ - } - else if(path_dirname(filepath) == "") { - /* .OSO File in search path */ - filepath = path_join(path_user_get("shaders"), filepath + ".oso"); - } - else { - /* unknown file */ - return NULL; - } - - /* test if we have loaded this .OSO already */ - const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time)); - - if(hash) - return hash; - } - - /* read oso bytecode from file */ - string bytecode_hash = shader_filepath_hash(filepath, modified_time); - string bytecode; - - if(!path_read_text(filepath, bytecode)) { - fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str()); - OSLShaderInfo info; - loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */ - return NULL; - } - - return shader_load_bytecode(bytecode_hash, bytecode); + size_t len = filepath.size(); + string extension = filepath.substr(len - 4); + uint64_t modified_time = path_modified_time(filepath); + + if (extension == ".osl") { + /* .OSL File */ + string osopath = filepath.substr(0, len - 4) + ".oso"; + uint64_t oso_modified_time = path_modified_time(osopath); + + /* test if we have loaded the corresponding .OSO already */ + if (oso_modified_time != 0) { + const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time)); + + if (hash) + return hash; + } + + /* autocompile .OSL to .OSO if needed */ + if (oso_modified_time == 0 || (oso_modified_time < modified_time)) { + OSLShaderManager::osl_compile(filepath, osopath); + modified_time = path_modified_time(osopath); + } + else + modified_time = oso_modified_time; + + filepath = osopath; + } + else { + if (extension == ".oso") { + /* .OSO File, nothing to do */ + } + else if (path_dirname(filepath) == "") { + /* .OSO File in search path */ + filepath = path_join(path_user_get("shaders"), filepath + ".oso"); + } + else { + /* unknown file */ + return NULL; + } + + /* test if we have loaded this .OSO already */ + const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time)); + + if (hash) + return hash; + } + + /* read oso bytecode from file */ + string bytecode_hash = shader_filepath_hash(filepath, modified_time); + string bytecode; + + if (!path_read_text(filepath, bytecode)) { + fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str()); + OSLShaderInfo info; + loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */ + return NULL; + } + + return shader_load_bytecode(bytecode_hash, bytecode); } -const char *OSLShaderManager::shader_load_bytecode(const string& hash, const string& bytecode) +const char *OSLShaderManager::shader_load_bytecode(const string &hash, const string &bytecode) { - ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str()); + ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str()); - OSLShaderInfo info; + OSLShaderInfo info; - if(!info.query.open_bytecode(bytecode)) { - fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str()); - } + if (!info.query.open_bytecode(bytecode)) { + fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str()); + } - /* this is a bit weak, but works */ - info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos); - info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos); - info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos); + /* this is a bit weak, but works */ + info.has_surface_emission = (bytecode.find("\"emission\"") != 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(); } -OSLNode *OSLShaderManager::osl_node(const std::string& filepath, - const std::string& bytecode_hash, - const std::string& bytecode) +OSLNode *OSLShaderManager::osl_node(const std::string &filepath, + const std::string &bytecode_hash, + const std::string &bytecode) { - /* create query */ - const char *hash; - - if(!filepath.empty()) { - hash = shader_load_filepath(filepath); - } - else { - hash = shader_test_loaded(bytecode_hash); - if(!hash) - hash = shader_load_bytecode(bytecode_hash, bytecode); - } - - if(!hash) { - return NULL; - } - - OSLShaderInfo *info = shader_loaded_info(hash); - - /* count number of inputs */ - size_t num_inputs = 0; - - for(int i = 0; i < info->query.nparams(); i++) { - const OSL::OSLQuery::Parameter *param = info->query.getparam(i); - - /* skip unsupported types */ - if(param->varlenarray || param->isstruct || param->type.arraylen > 1) - continue; - - if(!param->isoutput) - num_inputs++; - } - - /* create node */ - OSLNode *node = OSLNode::create(num_inputs); - - /* add new sockets from parameters */ - set<void*> used_sockets; - - for(int i = 0; i < info->query.nparams(); i++) { - const OSL::OSLQuery::Parameter *param = info->query.getparam(i); - - /* skip unsupported types */ - if(param->varlenarray || param->isstruct || param->type.arraylen > 1) - continue; - - SocketType::Type socket_type; - - if(param->isclosure) { - socket_type = SocketType::CLOSURE; - } - else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) { - if(param->type.vecsemantics == TypeDesc::COLOR) - socket_type = SocketType::COLOR; - else if(param->type.vecsemantics == TypeDesc::POINT) - socket_type = SocketType::POINT; - else if(param->type.vecsemantics == TypeDesc::VECTOR) - socket_type = SocketType::VECTOR; - else if(param->type.vecsemantics == TypeDesc::NORMAL) - socket_type = SocketType::NORMAL; - else - continue; - - if(!param->isoutput && param->validdefault) { - float3 *default_value = (float3*)node->input_default_value(); - default_value->x = param->fdefault[0]; - default_value->y = param->fdefault[1]; - default_value->z = param->fdefault[2]; - } - } - else if(param->type.aggregate == TypeDesc::SCALAR) { - if(param->type.basetype == TypeDesc::INT) { - socket_type = SocketType::INT; - - if(!param->isoutput && param->validdefault) { - *(int*)node->input_default_value() = param->idefault[0]; - } - } - else if(param->type.basetype == TypeDesc::FLOAT) { - socket_type = SocketType::FLOAT; - - if(!param->isoutput && param->validdefault) { - *(float*)node->input_default_value() = param->fdefault[0]; - } - } - else if(param->type.basetype == TypeDesc::STRING) { - socket_type = SocketType::STRING; - - if(!param->isoutput && param->validdefault) { - *(ustring*)node->input_default_value() = param->sdefault[0]; - } - } - else - continue; - } - else - continue; - - if(param->isoutput) { - node->add_output(param->name, socket_type); - } - else { - node->add_input(param->name, socket_type); - } - } - - /* set bytcode hash or filepath */ - if(!bytecode_hash.empty()) { - node->bytecode_hash = bytecode_hash; - } - else { - node->filepath = filepath; - } - - /* Generate inputs and outputs */ - node->create_inputs_outputs(node->type); - - return node; + /* create query */ + const char *hash; + + if (!filepath.empty()) { + hash = shader_load_filepath(filepath); + } + else { + hash = shader_test_loaded(bytecode_hash); + if (!hash) + hash = shader_load_bytecode(bytecode_hash, bytecode); + } + + if (!hash) { + return NULL; + } + + OSLShaderInfo *info = shader_loaded_info(hash); + + /* count number of inputs */ + size_t num_inputs = 0; + + for (int i = 0; i < info->query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = info->query.getparam(i); + + /* skip unsupported types */ + if (param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + if (!param->isoutput) + num_inputs++; + } + + /* create node */ + OSLNode *node = OSLNode::create(num_inputs); + + /* add new sockets from parameters */ + set<void *> used_sockets; + + for (int i = 0; i < info->query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = info->query.getparam(i); + + /* skip unsupported types */ + if (param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + SocketType::Type socket_type; + + if (param->isclosure) { + socket_type = SocketType::CLOSURE; + } + else if (param->type.vecsemantics != TypeDesc::NOSEMANTICS) { + if (param->type.vecsemantics == TypeDesc::COLOR) + socket_type = SocketType::COLOR; + else if (param->type.vecsemantics == TypeDesc::POINT) + socket_type = SocketType::POINT; + else if (param->type.vecsemantics == TypeDesc::VECTOR) + socket_type = SocketType::VECTOR; + else if (param->type.vecsemantics == TypeDesc::NORMAL) + socket_type = SocketType::NORMAL; + else + continue; + + if (!param->isoutput && param->validdefault) { + float3 *default_value = (float3 *)node->input_default_value(); + default_value->x = param->fdefault[0]; + default_value->y = param->fdefault[1]; + default_value->z = param->fdefault[2]; + } + } + else if (param->type.aggregate == TypeDesc::SCALAR) { + if (param->type.basetype == TypeDesc::INT) { + socket_type = SocketType::INT; + + if (!param->isoutput && param->validdefault) { + *(int *)node->input_default_value() = param->idefault[0]; + } + } + else if (param->type.basetype == TypeDesc::FLOAT) { + socket_type = SocketType::FLOAT; + + if (!param->isoutput && param->validdefault) { + *(float *)node->input_default_value() = param->fdefault[0]; + } + } + else if (param->type.basetype == TypeDesc::STRING) { + socket_type = SocketType::STRING; + + if (!param->isoutput && param->validdefault) { + *(ustring *)node->input_default_value() = param->sdefault[0]; + } + } + else + continue; + } + else + continue; + + if (param->isoutput) { + node->add_output(param->name, socket_type); + } + else { + node->add_input(param->name, socket_type); + } + } + + /* set bytcode hash or filepath */ + if (!bytecode_hash.empty()) { + node->bytecode_hash = bytecode_hash; + } + else { + node->filepath = filepath; + } + + /* Generate inputs and outputs */ + node->create_inputs_outputs(node->type); + + return node; } /* Graph Compiler */ -OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, +OSLCompiler::OSLCompiler(void *manager_, + void *shadingsys_, ImageManager *image_manager_, LightManager *light_manager_) { - manager = manager_; - shadingsys = shadingsys_; - image_manager = image_manager_; - light_manager = light_manager_; - current_type = SHADER_TYPE_SURFACE; - current_shader = NULL; - background = false; + manager = manager_; + shadingsys = shadingsys_; + image_manager = image_manager_; + light_manager = light_manager_; + current_type = SHADER_TYPE_SURFACE; + current_shader = NULL; + background = false; } string OSLCompiler::id(ShaderNode *node) { - /* assign layer unique name based on pointer address + bump mode */ - stringstream stream; - stream << "node_" << node->type->name << "_" << node; + /* assign layer unique name based on pointer address + bump mode */ + stringstream stream; + stream << "node_" << node->type->name << "_" << node; - return stream.str(); + return stream.str(); } string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input) { - string sname(input->name().string()); - size_t i; - - /* strip whitespace */ - while((i = sname.find(" ")) != string::npos) - sname.replace(i, 1, ""); - - /* if output exists with the same name, add "In" suffix */ - foreach(ShaderOutput *output, node->outputs) { - if(input->name() == output->name()) { - sname += "In"; - break; - } - } - - return sname; + string sname(input->name().string()); + size_t i; + + /* strip whitespace */ + while ((i = sname.find(" ")) != string::npos) + sname.replace(i, 1, ""); + + /* if output exists with the same name, add "In" suffix */ + foreach (ShaderOutput *output, node->outputs) { + if (input->name() == output->name()) { + sname += "In"; + break; + } + } + + return sname; } string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output) { - string sname(output->name().string()); - size_t i; - - /* strip whitespace */ - while((i = sname.find(" ")) != string::npos) - sname.replace(i, 1, ""); - - /* if input exists with the same name, add "Out" suffix */ - foreach(ShaderInput *input, node->inputs) { - if(input->name() == output->name()) { - sname += "Out"; - break; - } - } - - return sname; + string sname(output->name().string()); + size_t i; + + /* strip whitespace */ + while ((i = sname.find(" ")) != string::npos) + sname.replace(i, 1, ""); + + /* if input exists with the same name, add "Out" suffix */ + foreach (ShaderInput *input, node->inputs) { + if (input->name() == output->name()) { + sname += "Out"; + break; + } + } + + return sname; } bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input) { - /* exception for output node, only one input is actually used - * depending on the current shader type */ - - if(input->flags() & SocketType::SVM_INTERNAL) - return true; - - if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) { - if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE) - return true; - if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME) - return true; - if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT) - return true; - if(input->name() == "Normal" && current_type != SHADER_TYPE_BUMP) - return true; - } - else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) { - if(input->name() == "Height") - return true; - } - else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP) - return true; - - return false; + /* exception for output node, only one input is actually used + * depending on the current shader type */ + + if (input->flags() & SocketType::SVM_INTERNAL) + return true; + + if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) { + if (input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE) + return true; + if (input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME) + return true; + if (input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT) + return true; + if (input->name() == "Normal" && current_type != SHADER_TYPE_BUMP) + return true; + } + else if (node->special_type == SHADER_SPECIAL_TYPE_BUMP) { + if (input->name() == "Height") + return true; + } + else if (current_type == SHADER_TYPE_DISPLACEMENT && input->link && + input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP) + return true; + + return false; } void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - - /* load filepath */ - if(isfilepath) { - name = ((OSLShaderManager*)manager)->shader_load_filepath(name); - - if(name == NULL) - return; - } - - /* pass in fixed parameter values */ - foreach(ShaderInput *input, node->inputs) { - if(!input->link) { - /* checks to untangle graphs */ - if(node_skip_input(node, input)) - continue; - /* already has default value assigned */ - else if(input->flags() & SocketType::DEFAULT_LINK_MASK) - continue; - - string param_name = compatible_name(node, input); - const SocketType& socket = input->socket_type; - switch(input->type()) { - case SocketType::COLOR: - parameter_color(param_name.c_str(), node->get_float3(socket)); - break; - case SocketType::POINT: - parameter_point(param_name.c_str(), node->get_float3(socket)); - break; - case SocketType::VECTOR: - parameter_vector(param_name.c_str(), node->get_float3(socket)); - break; - case SocketType::NORMAL: - parameter_normal(param_name.c_str(), node->get_float3(socket)); - break; - case SocketType::FLOAT: - parameter(param_name.c_str(), node->get_float(socket)); - break; - case SocketType::INT: - parameter(param_name.c_str(), node->get_int(socket)); - break; - case SocketType::STRING: - parameter(param_name.c_str(), node->get_string(socket)); - break; - case SocketType::CLOSURE: - case SocketType::UNDEFINED: - default: - break; - } - } - } - - /* create shader of the appropriate type. OSL only distinguishes between "surface" - * and "displacement" atm */ - if(current_type == SHADER_TYPE_SURFACE) - ss->Shader("surface", name, id(node).c_str()); - else if(current_type == SHADER_TYPE_VOLUME) - ss->Shader("surface", name, id(node).c_str()); - else if(current_type == SHADER_TYPE_DISPLACEMENT) - ss->Shader("displacement", name, id(node).c_str()); - else if(current_type == SHADER_TYPE_BUMP) - ss->Shader("displacement", name, id(node).c_str()); - else - assert(0); - - /* link inputs to other nodes */ - foreach(ShaderInput *input, node->inputs) { - if(input->link) { - if(node_skip_input(node, input)) - continue; - - /* connect shaders */ - string id_from = id(input->link->parent); - string id_to = id(node); - string param_from = compatible_name(input->link->parent, input->link); - string param_to = compatible_name(node, input); - - ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str()); - } - } - - /* test if we shader contains specific closures */ - OSLShaderInfo *info = ((OSLShaderManager*)manager)->shader_loaded_info(name); - - if(current_type == SHADER_TYPE_SURFACE) { - if(info) { - if(info->has_surface_emission) - current_shader->has_surface_emission = true; - if(info->has_surface_transparent) - current_shader->has_surface_transparent = true; - if(info->has_surface_bssrdf) { - current_shader->has_surface_bssrdf = true; - current_shader->has_bssrdf_bump = true; /* can't detect yet */ - } - current_shader->has_bump = true; /* can't detect yet */ - } - - if(node->has_spatial_varying()) { - current_shader->has_surface_spatial_varying = true; - } - } - else if(current_type == SHADER_TYPE_VOLUME) { - if(node->has_spatial_varying()) - current_shader->has_volume_spatial_varying = true; - } - - if(node->has_object_dependency()) { - current_shader->has_object_dependency = true; - } - - if(node->has_attribute_dependency()) { - current_shader->has_attribute_dependency = true; - } - - if(node->has_integrator_dependency()) { - current_shader->has_integrator_dependency = true; - } + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + + /* load filepath */ + if (isfilepath) { + name = ((OSLShaderManager *)manager)->shader_load_filepath(name); + + if (name == NULL) + return; + } + + /* pass in fixed parameter values */ + foreach (ShaderInput *input, node->inputs) { + if (!input->link) { + /* checks to untangle graphs */ + if (node_skip_input(node, input)) + continue; + /* already has default value assigned */ + else if (input->flags() & SocketType::DEFAULT_LINK_MASK) + continue; + + string param_name = compatible_name(node, input); + const SocketType &socket = input->socket_type; + switch (input->type()) { + case SocketType::COLOR: + parameter_color(param_name.c_str(), node->get_float3(socket)); + break; + case SocketType::POINT: + parameter_point(param_name.c_str(), node->get_float3(socket)); + break; + case SocketType::VECTOR: + parameter_vector(param_name.c_str(), node->get_float3(socket)); + break; + case SocketType::NORMAL: + parameter_normal(param_name.c_str(), node->get_float3(socket)); + break; + case SocketType::FLOAT: + parameter(param_name.c_str(), node->get_float(socket)); + break; + case SocketType::INT: + parameter(param_name.c_str(), node->get_int(socket)); + break; + case SocketType::STRING: + parameter(param_name.c_str(), node->get_string(socket)); + break; + case SocketType::CLOSURE: + case SocketType::UNDEFINED: + default: + break; + } + } + } + + /* create shader of the appropriate type. OSL only distinguishes between "surface" + * and "displacement" atm */ + if (current_type == SHADER_TYPE_SURFACE) + ss->Shader("surface", name, id(node).c_str()); + else if (current_type == SHADER_TYPE_VOLUME) + ss->Shader("surface", name, id(node).c_str()); + else if (current_type == SHADER_TYPE_DISPLACEMENT) + ss->Shader("displacement", name, id(node).c_str()); + else if (current_type == SHADER_TYPE_BUMP) + ss->Shader("displacement", name, id(node).c_str()); + else + assert(0); + + /* link inputs to other nodes */ + foreach (ShaderInput *input, node->inputs) { + if (input->link) { + if (node_skip_input(node, input)) + continue; + + /* connect shaders */ + string id_from = id(input->link->parent); + string id_to = id(node); + string param_from = compatible_name(input->link->parent, input->link); + string param_to = compatible_name(node, input); + + ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str()); + } + } + + /* test if we shader contains specific closures */ + OSLShaderInfo *info = ((OSLShaderManager *)manager)->shader_loaded_info(name); + + if (current_type == SHADER_TYPE_SURFACE) { + if (info) { + if (info->has_surface_emission) + current_shader->has_surface_emission = true; + if (info->has_surface_transparent) + current_shader->has_surface_transparent = true; + if (info->has_surface_bssrdf) { + current_shader->has_surface_bssrdf = true; + current_shader->has_bssrdf_bump = true; /* can't detect yet */ + } + current_shader->has_bump = true; /* can't detect yet */ + } + + if (node->has_spatial_varying()) { + current_shader->has_surface_spatial_varying = true; + } + } + else if (current_type == SHADER_TYPE_VOLUME) { + if (node->has_spatial_varying()) + current_shader->has_volume_spatial_varying = true; + } + + if (node->has_object_dependency()) { + current_shader->has_object_dependency = true; + } + + if (node->has_attribute_dependency()) { + current_shader->has_attribute_dependency = true; + } + + if (node->has_integrator_dependency()) { + current_shader->has_integrator_dependency = true; + } } static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength) { - return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype, - (TypeDesc::AGGREGATE)typedesc.aggregate, - (TypeDesc::VECSEMANTICS)typedesc.vecsemantics, - arraylength); + return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype, + (TypeDesc::AGGREGATE)typedesc.aggregate, + (TypeDesc::VECSEMANTICS)typedesc.vecsemantics, + arraylength); } -void OSLCompiler::parameter(ShaderNode* node, const char *name) +void OSLCompiler::parameter(ShaderNode *node, const char *name) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ustring uname = ustring(name); - const SocketType& socket = *(node->type->find_input(uname)); - - switch(socket.type) - { - case SocketType::BOOLEAN: - { - int value = node->get_bool(socket); - ss->Parameter(name, TypeDesc::TypeInt, &value); - break; - } - case SocketType::FLOAT: - { - float value = node->get_float(socket); - ss->Parameter(uname, TypeDesc::TypeFloat, &value); - break; - } - case SocketType::INT: - { - int value = node->get_int(socket); - ss->Parameter(uname, TypeDesc::TypeInt, &value); - break; - } - case SocketType::COLOR: - { - float3 value = node->get_float3(socket); - ss->Parameter(uname, TypeDesc::TypeColor, &value); - break; - } - case SocketType::VECTOR: - { - float3 value = node->get_float3(socket); - ss->Parameter(uname, TypeDesc::TypeVector, &value); - break; - } - case SocketType::POINT: - { - float3 value = node->get_float3(socket); - ss->Parameter(uname, TypeDesc::TypePoint, &value); - break; - } - case SocketType::NORMAL: - { - float3 value = node->get_float3(socket); - ss->Parameter(uname, TypeDesc::TypeNormal, &value); - break; - } - case SocketType::POINT2: - { - float2 value = node->get_float2(socket); - ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value); - break; - } - case SocketType::STRING: - { - ustring value = node->get_string(socket); - ss->Parameter(uname, TypeDesc::TypeString, &value); - break; - } - case SocketType::ENUM: - { - ustring value = node->get_string(socket); - ss->Parameter(uname, TypeDesc::TypeString, &value); - break; - } - case SocketType::TRANSFORM: - { - Transform value = node->get_transform(socket); - ProjectionTransform projection(value); - projection = projection_transpose(projection); - ss->Parameter(uname, TypeDesc::TypeMatrix, &projection); - break; - } - case SocketType::BOOLEAN_ARRAY: - { - // OSL does not support booleans, so convert to int - const array<bool>& value = node->get_bool_array(socket); - array<int> intvalue(value.size()); - for(size_t i = 0; i < value.size(); i++) - intvalue[i] = value[i]; - ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data()); - break; - } - case SocketType::FLOAT_ARRAY: - { - const array<float>& value = node->get_float_array(socket); - ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data()); - break; - } - case SocketType::INT_ARRAY: - { - const array<int>& value = node->get_int_array(socket); - ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data()); - break; - } - case SocketType::COLOR_ARRAY: - case SocketType::VECTOR_ARRAY: - case SocketType::POINT_ARRAY: - case SocketType::NORMAL_ARRAY: - { - TypeDesc typedesc; - - switch(socket.type) - { - case SocketType::COLOR_ARRAY: typedesc = TypeDesc::TypeColor; break; - case SocketType::VECTOR_ARRAY: typedesc = TypeDesc::TypeVector; break; - case SocketType::POINT_ARRAY: typedesc = TypeDesc::TypePoint; break; - case SocketType::NORMAL_ARRAY: typedesc = TypeDesc::TypeNormal; break; - default: assert(0); break; - } - - // convert to tightly packed array since float3 has padding - const array<float3>& value = node->get_float3_array(socket); - array<float> fvalue(value.size() * 3); - for(size_t i = 0, j = 0; i < value.size(); i++) { - fvalue[j++] = value[i].x; - fvalue[j++] = value[i].y; - fvalue[j++] = value[i].z; - } - - ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data()); - break; - } - case SocketType::POINT2_ARRAY: - { - const array<float2>& value = node->get_float2_array(socket); - ss->Parameter(uname, array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()), value.data()); - break; - } - case SocketType::STRING_ARRAY: - { - const array<ustring>& value = node->get_string_array(socket); - ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data()); - break; - } - case SocketType::TRANSFORM_ARRAY: - { - const array<Transform>& value = node->get_transform_array(socket); - array<ProjectionTransform> fvalue(value.size()); - for(size_t i = 0; i < value.size(); i++) { - fvalue[i] = projection_transpose(ProjectionTransform(value[i])); - } - ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data()); - break; - } - case SocketType::CLOSURE: - case SocketType::NODE: - case SocketType::NODE_ARRAY: - case SocketType::UNDEFINED: - case SocketType::UINT: - { - assert(0); - break; - } - } + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ustring uname = ustring(name); + const SocketType &socket = *(node->type->find_input(uname)); + + switch (socket.type) { + case SocketType::BOOLEAN: { + int value = node->get_bool(socket); + ss->Parameter(name, TypeDesc::TypeInt, &value); + break; + } + case SocketType::FLOAT: { + float value = node->get_float(socket); + ss->Parameter(uname, TypeDesc::TypeFloat, &value); + break; + } + case SocketType::INT: { + int value = node->get_int(socket); + ss->Parameter(uname, TypeDesc::TypeInt, &value); + break; + } + case SocketType::COLOR: { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeColor, &value); + break; + } + case SocketType::VECTOR: { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeVector, &value); + break; + } + case SocketType::POINT: { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypePoint, &value); + break; + } + case SocketType::NORMAL: { + float3 value = node->get_float3(socket); + ss->Parameter(uname, TypeDesc::TypeNormal, &value); + break; + } + case SocketType::POINT2: { + float2 value = node->get_float2(socket); + ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value); + break; + } + case SocketType::STRING: { + ustring value = node->get_string(socket); + ss->Parameter(uname, TypeDesc::TypeString, &value); + break; + } + case SocketType::ENUM: { + ustring value = node->get_string(socket); + ss->Parameter(uname, TypeDesc::TypeString, &value); + break; + } + case SocketType::TRANSFORM: { + Transform value = node->get_transform(socket); + ProjectionTransform projection(value); + projection = projection_transpose(projection); + ss->Parameter(uname, TypeDesc::TypeMatrix, &projection); + break; + } + case SocketType::BOOLEAN_ARRAY: { + // OSL does not support booleans, so convert to int + const array<bool> &value = node->get_bool_array(socket); + array<int> intvalue(value.size()); + for (size_t i = 0; i < value.size(); i++) + intvalue[i] = value[i]; + ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data()); + break; + } + case SocketType::FLOAT_ARRAY: { + const array<float> &value = node->get_float_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data()); + break; + } + case SocketType::INT_ARRAY: { + const array<int> &value = node->get_int_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data()); + break; + } + case SocketType::COLOR_ARRAY: + case SocketType::VECTOR_ARRAY: + case SocketType::POINT_ARRAY: + case SocketType::NORMAL_ARRAY: { + TypeDesc typedesc; + + switch (socket.type) { + case SocketType::COLOR_ARRAY: + typedesc = TypeDesc::TypeColor; + break; + case SocketType::VECTOR_ARRAY: + typedesc = TypeDesc::TypeVector; + break; + case SocketType::POINT_ARRAY: + typedesc = TypeDesc::TypePoint; + break; + case SocketType::NORMAL_ARRAY: + typedesc = TypeDesc::TypeNormal; + break; + default: + assert(0); + break; + } + + // convert to tightly packed array since float3 has padding + const array<float3> &value = node->get_float3_array(socket); + array<float> fvalue(value.size() * 3); + for (size_t i = 0, j = 0; i < value.size(); i++) { + fvalue[j++] = value[i].x; + fvalue[j++] = value[i].y; + fvalue[j++] = value[i].z; + } + + ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data()); + break; + } + case SocketType::POINT2_ARRAY: { + const array<float2> &value = node->get_float2_array(socket); + ss->Parameter( + uname, + array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()), + value.data()); + break; + } + case SocketType::STRING_ARRAY: { + const array<ustring> &value = node->get_string_array(socket); + ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data()); + break; + } + case SocketType::TRANSFORM_ARRAY: { + const array<Transform> &value = node->get_transform_array(socket); + array<ProjectionTransform> fvalue(value.size()); + for (size_t i = 0; i < value.size(); i++) { + fvalue[i] = projection_transpose(ProjectionTransform(value[i])); + } + ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data()); + break; + } + case SocketType::CLOSURE: + case SocketType::NODE: + case SocketType::NODE_ARRAY: + case SocketType::UNDEFINED: + case SocketType::UINT: { + assert(0); + break; + } + } } void OSLCompiler::parameter(const char *name, float f) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypeFloat, &f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypeFloat, &f); } void OSLCompiler::parameter_color(const char *name, float3 f) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypeColor, &f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypeColor, &f); } void OSLCompiler::parameter_point(const char *name, float3 f) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypePoint, &f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypePoint, &f); } void OSLCompiler::parameter_normal(const char *name, float3 f) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypeNormal, &f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypeNormal, &f); } void OSLCompiler::parameter_vector(const char *name, float3 f) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypeVector, &f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypeVector, &f); } void OSLCompiler::parameter(const char *name, int f) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypeInt, &f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypeInt, &f); } void OSLCompiler::parameter(const char *name, const char *s) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ss->Parameter(name, TypeDesc::TypeString, &s); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ss->Parameter(name, TypeDesc::TypeString, &s); } void OSLCompiler::parameter(const char *name, ustring s) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - const char *str = s.c_str(); - ss->Parameter(name, TypeDesc::TypeString, &str); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + const char *str = s.c_str(); + ss->Parameter(name, TypeDesc::TypeString, &str); } -void OSLCompiler::parameter(const char *name, const Transform& tfm) +void OSLCompiler::parameter(const char *name, const Transform &tfm) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - ProjectionTransform projection(tfm); - projection = projection_transpose(projection); - ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&projection); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + ProjectionTransform projection(tfm); + projection = projection_transpose(projection); + ss->Parameter(name, TypeDesc::TypeMatrix, (float *)&projection); } void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - TypeDesc type = TypeDesc::TypeFloat; - type.arraylen = arraylen; - ss->Parameter(name, type, f); + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + TypeDesc type = TypeDesc::TypeFloat; + type.arraylen = arraylen; + ss->Parameter(name, type, f); } -void OSLCompiler::parameter_color_array(const char *name, const array<float3>& f) +void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f) { - /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */ - array<float[3]> table(f.size()); - - for(int i = 0; i < f.size(); ++i) { - table[i][0] = f[i].x; - table[i][1] = f[i].y; - table[i][2] = f[i].z; - } - - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - TypeDesc type = TypeDesc::TypeColor; - type.arraylen = table.size(); - ss->Parameter(name, type, table.data()); + /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */ + array<float[3]> table(f.size()); + + for (int i = 0; i < f.size(); ++i) { + table[i][0] = f[i].x; + table[i][1] = f[i].y; + table[i][2] = f[i].z; + } + + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + TypeDesc type = TypeDesc::TypeColor; + type.arraylen = table.size(); + ss->Parameter(name, type, table.data()); } void OSLCompiler::parameter_attribute(const char *name, ustring s) { - if(Attribute::name_standard(s.c_str())) - parameter(name, (string("geom:") + s.c_str()).c_str()); - else - parameter(name, s.c_str()); + if (Attribute::name_standard(s.c_str())) + parameter(name, (string("geom:") + s.c_str()).c_str()); + else + parameter(name, s.c_str()); } -void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input) +void OSLCompiler::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input) { - ShaderNode *node = (input->link)? input->link->parent: NULL; + ShaderNode *node = (input->link) ? input->link->parent : NULL; - if(node != NULL && dependencies.find(node) == dependencies.end()) { - foreach(ShaderInput *in, node->inputs) - if(!node_skip_input(node, in)) - find_dependencies(dependencies, in); + if (node != NULL && dependencies.find(node) == dependencies.end()) { + foreach (ShaderInput *in, node->inputs) + if (!node_skip_input(node, in)) + find_dependencies(dependencies, in); - dependencies.insert(node); - } + dependencies.insert(node); + } } -void OSLCompiler::generate_nodes(const ShaderNodeSet& nodes) +void OSLCompiler::generate_nodes(const ShaderNodeSet &nodes) { - ShaderNodeSet done; - bool nodes_done; - - do { - nodes_done = true; - - foreach(ShaderNode *node, nodes) { - if(done.find(node) == done.end()) { - bool inputs_done = true; - - foreach(ShaderInput *input, node->inputs) - if(!node_skip_input(node, input)) - if(input->link && done.find(input->link->parent) == done.end()) - inputs_done = false; - - if(inputs_done) { - node->compile(*this); - done.insert(node); - - if(current_type == SHADER_TYPE_SURFACE) { - if(node->has_surface_emission()) - current_shader->has_surface_emission = true; - if(node->has_surface_transparent()) - current_shader->has_surface_transparent = true; - if(node->has_spatial_varying()) - current_shader->has_surface_spatial_varying = true; - if(node->has_surface_bssrdf()) { - current_shader->has_surface_bssrdf = true; - if(node->has_bssrdf_bump()) - current_shader->has_bssrdf_bump = true; - } - if(node->has_bump()) { - current_shader->has_bump = true; - } - } - else if(current_type == SHADER_TYPE_VOLUME) { - if(node->has_spatial_varying()) - current_shader->has_volume_spatial_varying = true; - } - } - else - nodes_done = false; - } - } - } while(!nodes_done); + ShaderNodeSet done; + bool nodes_done; + + do { + nodes_done = true; + + foreach (ShaderNode *node, nodes) { + if (done.find(node) == done.end()) { + bool inputs_done = true; + + foreach (ShaderInput *input, node->inputs) + if (!node_skip_input(node, input)) + if (input->link && done.find(input->link->parent) == done.end()) + inputs_done = false; + + if (inputs_done) { + node->compile(*this); + done.insert(node); + + if (current_type == SHADER_TYPE_SURFACE) { + if (node->has_surface_emission()) + current_shader->has_surface_emission = true; + if (node->has_surface_transparent()) + current_shader->has_surface_transparent = true; + if (node->has_spatial_varying()) + current_shader->has_surface_spatial_varying = true; + if (node->has_surface_bssrdf()) { + current_shader->has_surface_bssrdf = true; + if (node->has_bssrdf_bump()) + current_shader->has_bssrdf_bump = true; + } + if (node->has_bump()) { + current_shader->has_bump = true; + } + } + else if (current_type == SHADER_TYPE_VOLUME) { + if (node->has_spatial_varying()) + current_shader->has_volume_spatial_varying = true; + } + } + else + nodes_done = false; + } + } + } while (!nodes_done); } OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) { - OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys; - - current_type = type; - - OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str()); - - ShaderNode *output = graph->output(); - ShaderNodeSet dependencies; - - if(type == SHADER_TYPE_SURFACE) { - /* generate surface shader */ - find_dependencies(dependencies, output->input("Surface")); - generate_nodes(dependencies); - output->compile(*this); - } - else if(type == SHADER_TYPE_BUMP) { - /* generate bump shader */ - find_dependencies(dependencies, output->input("Normal")); - generate_nodes(dependencies); - output->compile(*this); - } - else if(type == SHADER_TYPE_VOLUME) { - /* generate volume shader */ - find_dependencies(dependencies, output->input("Volume")); - generate_nodes(dependencies); - output->compile(*this); - } - else if(type == SHADER_TYPE_DISPLACEMENT) { - /* generate displacement shader */ - find_dependencies(dependencies, output->input("Displacement")); - generate_nodes(dependencies); - output->compile(*this); - } - else - assert(0); - - ss->ShaderGroupEnd(); - - return group; + OSL::ShadingSystem *ss = (OSL::ShadingSystem *)shadingsys; + + current_type = type; + + OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str()); + + ShaderNode *output = graph->output(); + ShaderNodeSet dependencies; + + if (type == SHADER_TYPE_SURFACE) { + /* generate surface shader */ + find_dependencies(dependencies, output->input("Surface")); + generate_nodes(dependencies); + output->compile(*this); + } + else if (type == SHADER_TYPE_BUMP) { + /* generate bump shader */ + find_dependencies(dependencies, output->input("Normal")); + generate_nodes(dependencies); + output->compile(*this); + } + else if (type == SHADER_TYPE_VOLUME) { + /* generate volume shader */ + find_dependencies(dependencies, output->input("Volume")); + generate_nodes(dependencies); + output->compile(*this); + } + else if (type == SHADER_TYPE_DISPLACEMENT) { + /* generate displacement shader */ + find_dependencies(dependencies, output->input("Displacement")); + generate_nodes(dependencies); + output->compile(*this); + } + else + assert(0); + + ss->ShaderGroupEnd(); + + return group; } void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader) { - if(shader->need_update) { - ShaderGraph *graph = shader->graph; - ShaderNode *output = (graph)? graph->output(): NULL; - - bool has_bump = (shader->displacement_method != DISPLACE_TRUE) && - output->input("Surface")->link && output->input("Displacement")->link; - - /* finalize */ - shader->graph->finalize(scene, - has_bump, - shader->has_integrator_dependency, - shader->displacement_method == DISPLACE_BOTH); - - current_shader = shader; - - shader->has_surface = false; - shader->has_surface_emission = false; - shader->has_surface_transparent = false; - shader->has_surface_bssrdf = false; - shader->has_bump = has_bump; - shader->has_bssrdf_bump = has_bump; - shader->has_volume = false; - shader->has_displacement = false; - shader->has_surface_spatial_varying = false; - shader->has_volume_spatial_varying = false; - shader->has_object_dependency = false; - shader->has_attribute_dependency = false; - shader->has_integrator_dependency = false; - - /* generate surface shader */ - if(shader->used && graph && output->input("Surface")->link) { - shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); - - if(has_bump) - shader->osl_surface_bump_ref = compile_type(shader, shader->graph, SHADER_TYPE_BUMP); - else - shader->osl_surface_bump_ref = OSL::ShaderGroupRef(); - - shader->has_surface = true; - } - else { - shader->osl_surface_ref = OSL::ShaderGroupRef(); - shader->osl_surface_bump_ref = OSL::ShaderGroupRef(); - } - - /* generate volume shader */ - if(shader->used && graph && output->input("Volume")->link) { - shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); - shader->has_volume = true; - } - else - shader->osl_volume_ref = OSL::ShaderGroupRef(); - - /* generate displacement shader */ - if(shader->used && graph && output->input("Displacement")->link) { - shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); - shader->has_displacement = true; - } - else - shader->osl_displacement_ref = OSL::ShaderGroupRef(); - } - - /* push state to array for lookup */ - og->surface_state.push_back(shader->osl_surface_ref); - og->volume_state.push_back(shader->osl_volume_ref); - og->displacement_state.push_back(shader->osl_displacement_ref); - og->bump_state.push_back(shader->osl_surface_bump_ref); + if (shader->need_update) { + ShaderGraph *graph = shader->graph; + ShaderNode *output = (graph) ? graph->output() : NULL; + + bool has_bump = (shader->displacement_method != DISPLACE_TRUE) && + output->input("Surface")->link && output->input("Displacement")->link; + + /* finalize */ + shader->graph->finalize(scene, + has_bump, + shader->has_integrator_dependency, + shader->displacement_method == DISPLACE_BOTH); + + current_shader = shader; + + shader->has_surface = false; + shader->has_surface_emission = false; + shader->has_surface_transparent = false; + shader->has_surface_bssrdf = false; + shader->has_bump = has_bump; + shader->has_bssrdf_bump = has_bump; + shader->has_volume = false; + shader->has_displacement = false; + shader->has_surface_spatial_varying = false; + shader->has_volume_spatial_varying = false; + shader->has_object_dependency = false; + shader->has_attribute_dependency = false; + shader->has_integrator_dependency = false; + + /* generate surface shader */ + if (shader->used && graph && output->input("Surface")->link) { + shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); + + if (has_bump) + shader->osl_surface_bump_ref = compile_type(shader, shader->graph, SHADER_TYPE_BUMP); + else + shader->osl_surface_bump_ref = OSL::ShaderGroupRef(); + + shader->has_surface = true; + } + else { + shader->osl_surface_ref = OSL::ShaderGroupRef(); + shader->osl_surface_bump_ref = OSL::ShaderGroupRef(); + } + + /* generate volume shader */ + if (shader->used && graph && output->input("Volume")->link) { + shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); + shader->has_volume = true; + } + else + shader->osl_volume_ref = OSL::ShaderGroupRef(); + + /* generate displacement shader */ + if (shader->used && graph && output->input("Displacement")->link) { + shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); + shader->has_displacement = true; + } + else + shader->osl_displacement_ref = OSL::ShaderGroupRef(); + } + + /* push state to array for lookup */ + og->surface_state.push_back(shader->osl_surface_ref); + og->volume_state.push_back(shader->osl_volume_ref); + og->displacement_state.push_back(shader->osl_displacement_ref); + og->bump_state.push_back(shader->osl_surface_bump_ref); } #else @@ -1247,7 +1236,7 @@ void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/) { } -void OSLCompiler::parameter(const char * /*name*/, const Transform& /*tfm*/) +void OSLCompiler::parameter(const char * /*name*/, const Transform & /*tfm*/) { } @@ -1255,10 +1244,10 @@ void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], in { } -void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3>& /*f*/) +void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3> & /*f*/) { } -#endif /* WITH_OSL */ +#endif /* WITH_OSL */ CCL_NAMESPACE_END diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 93cc3139608..aec518a6c2b 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -27,10 +27,10 @@ #include "render/shader.h" #ifdef WITH_OSL -#include <OSL/llvm_util.h> -#include <OSL/oslcomp.h> -#include <OSL/oslexec.h> -#include <OSL/oslquery.h> +# include <OSL/llvm_util.h> +# include <OSL/oslcomp.h> +# include <OSL/oslexec.h> +# include <OSL/oslquery.h> #endif CCL_NAMESPACE_BEGIN @@ -52,70 +52,73 @@ class ShaderOutput; * to auto detect closures in the shader for MIS and transparent shadows */ struct OSLShaderInfo { - OSLShaderInfo() - : has_surface_emission(false), has_surface_transparent(false), - has_surface_bssrdf(false) - {} - - OSL::OSLQuery query; - bool has_surface_emission; - bool has_surface_transparent; - bool has_surface_bssrdf; + OSLShaderInfo() + : has_surface_emission(false), has_surface_transparent(false), has_surface_bssrdf(false) + { + } + + OSL::OSLQuery query; + bool has_surface_emission; + bool has_surface_transparent; + bool has_surface_bssrdf; }; /* Shader Manage */ class OSLShaderManager : public ShaderManager { -public: - OSLShaderManager(); - ~OSLShaderManager(); - - static void free_memory(); - - void reset(Scene *scene); - - bool use_osl() { return true; } - - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_free(Device *device, DeviceScene *dscene, Scene *scene); - - /* osl compile and query */ - static bool osl_compile(const string& inputfile, const string& outputfile); - static bool osl_query(OSL::OSLQuery& query, const string& filepath); - - /* shader file loading, all functions return pointer to hash string if found */ - const char *shader_test_loaded(const string& hash); - const char *shader_load_bytecode(const string& hash, const string& bytecode); - const char *shader_load_filepath(string filepath); - OSLShaderInfo *shader_loaded_info(const string& hash); - - /* create OSL node using OSLQuery */ - OSLNode *osl_node(const std::string& filepath, - const std::string& bytecode_hash = "", - const std::string& bytecode = ""); - -protected: - void texture_system_init(); - void texture_system_free(); - - void shading_system_init(); - void shading_system_free(); - - OSL::ShadingSystem *ss; - OSL::TextureSystem *ts; - OSLRenderServices *services; - OSL::ErrorHandler errhandler; - map<string, OSLShaderInfo> loaded_shaders; - - static OSL::TextureSystem *ts_shared; - static thread_mutex ts_shared_mutex; - static int ts_shared_users; - - static OSL::ShadingSystem *ss_shared; - static OSLRenderServices *services_shared; - static thread_mutex ss_shared_mutex; - static thread_mutex ss_mutex; - static int ss_shared_users; + public: + OSLShaderManager(); + ~OSLShaderManager(); + + static void free_memory(); + + void reset(Scene *scene); + + bool use_osl() + { + return true; + } + + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free(Device *device, DeviceScene *dscene, Scene *scene); + + /* osl compile and query */ + static bool osl_compile(const string &inputfile, const string &outputfile); + static bool osl_query(OSL::OSLQuery &query, const string &filepath); + + /* shader file loading, all functions return pointer to hash string if found */ + const char *shader_test_loaded(const string &hash); + const char *shader_load_bytecode(const string &hash, const string &bytecode); + const char *shader_load_filepath(string filepath); + OSLShaderInfo *shader_loaded_info(const string &hash); + + /* create OSL node using OSLQuery */ + OSLNode *osl_node(const std::string &filepath, + const std::string &bytecode_hash = "", + const std::string &bytecode = ""); + + protected: + void texture_system_init(); + void texture_system_free(); + + void shading_system_init(); + void shading_system_free(); + + OSL::ShadingSystem *ss; + OSL::TextureSystem *ts; + OSLRenderServices *services; + OSL::ErrorHandler errhandler; + map<string, OSLShaderInfo> loaded_shaders; + + static OSL::TextureSystem *ts_shared; + static thread_mutex ts_shared_mutex; + static int ts_shared_users; + + static OSL::ShadingSystem *ss_shared; + static OSLRenderServices *services_shared; + static thread_mutex ss_shared_mutex; + static thread_mutex ss_mutex; + static int ss_shared_users; }; #endif @@ -123,55 +126,59 @@ protected: /* Graph Compiler */ class OSLCompiler { -public: - OSLCompiler(void *manager, void *shadingsys, - ImageManager *image_manager, - LightManager *light_manager); - void compile(Scene *scene, OSLGlobals *og, Shader *shader); - - void add(ShaderNode *node, const char *name, bool isfilepath = false); - - void parameter(ShaderNode *node, const char *name); - - void parameter(const char *name, float f); - void parameter_color(const char *name, float3 f); - void parameter_vector(const char *name, float3 f); - void parameter_normal(const char *name, float3 f); - void parameter_point(const char *name, float3 f); - void parameter(const char *name, int f); - void parameter(const char *name, const char *s); - void parameter(const char *name, ustring str); - void parameter(const char *name, const Transform& tfm); - - void parameter_array(const char *name, const float f[], int arraylen); - void parameter_color_array(const char *name, const array<float3>& f); - - void parameter_attribute(const char *name, ustring s); - - ShaderType output_type() { return current_type; } - - bool background; - ImageManager *image_manager; - LightManager *light_manager; - -private: + public: + OSLCompiler(void *manager, + void *shadingsys, + ImageManager *image_manager, + LightManager *light_manager); + void compile(Scene *scene, OSLGlobals *og, Shader *shader); + + void add(ShaderNode *node, const char *name, bool isfilepath = false); + + void parameter(ShaderNode *node, const char *name); + + void parameter(const char *name, float f); + void parameter_color(const char *name, float3 f); + void parameter_vector(const char *name, float3 f); + void parameter_normal(const char *name, float3 f); + void parameter_point(const char *name, float3 f); + void parameter(const char *name, int f); + void parameter(const char *name, const char *s); + void parameter(const char *name, ustring str); + void parameter(const char *name, const Transform &tfm); + + void parameter_array(const char *name, const float f[], int arraylen); + void parameter_color_array(const char *name, const array<float3> &f); + + void parameter_attribute(const char *name, ustring s); + + ShaderType output_type() + { + return current_type; + } + + bool background; + ImageManager *image_manager; + LightManager *light_manager; + + private: #ifdef WITH_OSL - string id(ShaderNode *node); - OSL::ShaderGroupRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); - bool node_skip_input(ShaderNode *node, ShaderInput *input); - string compatible_name(ShaderNode *node, ShaderInput *input); - string compatible_name(ShaderNode *node, ShaderOutput *output); - - void find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input); - void generate_nodes(const ShaderNodeSet& nodes); + string id(ShaderNode *node); + OSL::ShaderGroupRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); + bool node_skip_input(ShaderNode *node, ShaderInput *input); + string compatible_name(ShaderNode *node, ShaderInput *input); + string compatible_name(ShaderNode *node, ShaderOutput *output); + + void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input); + void generate_nodes(const ShaderNodeSet &nodes); #endif - void *shadingsys; - void *manager; - ShaderType current_type; - Shader *current_shader; + void *shadingsys; + void *manager; + ShaderType current_type; + Shader *current_shader; }; CCL_NAMESPACE_END -#endif /* __OSL_H__ */ +#endif /* __OSL_H__ */ diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp index 0583556c8a9..8335404b197 100644 --- a/intern/cycles/render/particles.cpp +++ b/intern/cycles/render/particles.cpp @@ -39,86 +39,93 @@ ParticleSystem::~ParticleSystem() void ParticleSystem::tag_update(Scene *scene) { - scene->particle_system_manager->need_update = true; + scene->particle_system_manager->need_update = true; } /* Particle System Manager */ ParticleSystemManager::ParticleSystemManager() { - need_update = true; + need_update = true; } ParticleSystemManager::~ParticleSystemManager() { } -void ParticleSystemManager::device_update_particles(Device *, DeviceScene *dscene, Scene *scene, Progress& progress) +void ParticleSystemManager::device_update_particles(Device *, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - /* count particles. - * adds one dummy particle at the beginning to avoid invalid lookups, - * in case a shader uses particle info without actual particle data. */ - int num_particles = 1; - for(size_t j = 0; j < scene->particle_systems.size(); j++) - num_particles += scene->particle_systems[j]->particles.size(); - - KernelParticle *kparticles = dscene->particles.alloc(num_particles); - - /* dummy particle */ - memset(kparticles, 0, sizeof(KernelParticle)); - - int i = 1; - for(size_t j = 0; j < scene->particle_systems.size(); j++) { - ParticleSystem *psys = scene->particle_systems[j]; - - for(size_t k = 0; k < psys->particles.size(); k++) { - /* pack in texture */ - Particle& pa = psys->particles[k]; - - kparticles[i].index = pa.index; - kparticles[i].age = pa.age; - kparticles[i].lifetime = pa.lifetime; - kparticles[i].size = pa.size; - kparticles[i].rotation = pa.rotation; - kparticles[i].location = float3_to_float4(pa.location); - kparticles[i].velocity = float3_to_float4(pa.velocity); - kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity); - - i++; - - if(progress.get_cancel()) return; - } - } - - dscene->particles.copy_to_device(); + /* count particles. + * adds one dummy particle at the beginning to avoid invalid lookups, + * in case a shader uses particle info without actual particle data. */ + int num_particles = 1; + for (size_t j = 0; j < scene->particle_systems.size(); j++) + num_particles += scene->particle_systems[j]->particles.size(); + + KernelParticle *kparticles = dscene->particles.alloc(num_particles); + + /* dummy particle */ + memset(kparticles, 0, sizeof(KernelParticle)); + + int i = 1; + for (size_t j = 0; j < scene->particle_systems.size(); j++) { + ParticleSystem *psys = scene->particle_systems[j]; + + for (size_t k = 0; k < psys->particles.size(); k++) { + /* pack in texture */ + Particle &pa = psys->particles[k]; + + kparticles[i].index = pa.index; + kparticles[i].age = pa.age; + kparticles[i].lifetime = pa.lifetime; + kparticles[i].size = pa.size; + kparticles[i].rotation = pa.rotation; + kparticles[i].location = float3_to_float4(pa.location); + kparticles[i].velocity = float3_to_float4(pa.velocity); + kparticles[i].angular_velocity = float3_to_float4(pa.angular_velocity); + + i++; + + if (progress.get_cancel()) + return; + } + } + + dscene->particles.copy_to_device(); } -void ParticleSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void ParticleSystemManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - VLOG(1) << "Total " << scene->particle_systems.size() - << " particle systems."; + VLOG(1) << "Total " << scene->particle_systems.size() << " particle systems."; - device_free(device, dscene); + device_free(device, dscene); - progress.set_status("Updating Particle Systems", "Copying Particles to device"); - device_update_particles(device, dscene, scene, progress); + progress.set_status("Updating Particle Systems", "Copying Particles to device"); + device_update_particles(device, dscene, scene, progress); - if(progress.get_cancel()) return; + if (progress.get_cancel()) + return; - need_update = false; + need_update = false; } void ParticleSystemManager::device_free(Device *, DeviceScene *dscene) { - dscene->particles.free(); + dscene->particles.free(); } void ParticleSystemManager::tag_update(Scene * /*scene*/) { - need_update = true; + need_update = true; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h index 27821907af0..65663c31c37 100644 --- a/intern/cycles/render/particles.h +++ b/intern/cycles/render/particles.h @@ -30,42 +30,45 @@ class Scene; /* Particle System */ struct Particle { - int index; - float age; - float lifetime; - float3 location; - float4 rotation; - float size; - float3 velocity; - float3 angular_velocity; + int index; + float age; + float lifetime; + float3 location; + float4 rotation; + float size; + float3 velocity; + float3 angular_velocity; }; class ParticleSystem { -public: - ParticleSystem(); - ~ParticleSystem(); + public: + ParticleSystem(); + ~ParticleSystem(); - void tag_update(Scene *scene); + void tag_update(Scene *scene); - array<Particle> particles; + array<Particle> particles; }; /* ParticleSystem Manager */ class ParticleSystemManager { -public: - bool need_update; + public: + bool need_update; - ParticleSystemManager(); - ~ParticleSystemManager(); + ParticleSystemManager(); + ~ParticleSystemManager(); - void device_update_particles(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_update_particles(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 tag_update(Scene *scene); + void tag_update(Scene *scene); }; CCL_NAMESPACE_END -#endif /* __PARTICLES_H__ */ +#endif /* __PARTICLES_H__ */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 1f551f206ef..1e75fa0f99b 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -41,352 +41,359 @@ CCL_NAMESPACE_BEGIN DeviceScene::DeviceScene(Device *device) -: bvh_nodes(device, "__bvh_nodes", MEM_TEXTURE), - bvh_leaf_nodes(device, "__bvh_leaf_nodes", MEM_TEXTURE), - object_node(device, "__object_node", MEM_TEXTURE), - prim_tri_index(device, "__prim_tri_index", MEM_TEXTURE), - prim_tri_verts(device, "__prim_tri_verts", MEM_TEXTURE), - prim_type(device, "__prim_type", MEM_TEXTURE), - prim_visibility(device, "__prim_visibility", MEM_TEXTURE), - prim_index(device, "__prim_index", MEM_TEXTURE), - prim_object(device, "__prim_object", MEM_TEXTURE), - prim_time(device, "__prim_time", MEM_TEXTURE), - tri_shader(device, "__tri_shader", MEM_TEXTURE), - tri_vnormal(device, "__tri_vnormal", MEM_TEXTURE), - tri_vindex(device, "__tri_vindex", MEM_TEXTURE), - tri_patch(device, "__tri_patch", MEM_TEXTURE), - tri_patch_uv(device, "__tri_patch_uv", MEM_TEXTURE), - curves(device, "__curves", MEM_TEXTURE), - curve_keys(device, "__curve_keys", MEM_TEXTURE), - patches(device, "__patches", MEM_TEXTURE), - objects(device, "__objects", MEM_TEXTURE), - object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE), - object_motion(device, "__object_motion", MEM_TEXTURE), - object_flag(device, "__object_flag", MEM_TEXTURE), - camera_motion(device, "__camera_motion", MEM_TEXTURE), - attributes_map(device, "__attributes_map", MEM_TEXTURE), - attributes_float(device, "__attributes_float", MEM_TEXTURE), - attributes_float2(device, "__attributes_float2", MEM_TEXTURE), - attributes_float3(device, "__attributes_float3", MEM_TEXTURE), - attributes_uchar4(device, "__attributes_uchar4", MEM_TEXTURE), - light_distribution(device, "__light_distribution", MEM_TEXTURE), - lights(device, "__lights", MEM_TEXTURE), - light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_TEXTURE), - light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_TEXTURE), - particles(device, "__particles", MEM_TEXTURE), - svm_nodes(device, "__svm_nodes", MEM_TEXTURE), - shaders(device, "__shaders", MEM_TEXTURE), - lookup_table(device, "__lookup_table", MEM_TEXTURE), - sobol_directions(device, "__sobol_directions", MEM_TEXTURE), - ies_lights(device, "__ies", MEM_TEXTURE) + : bvh_nodes(device, "__bvh_nodes", MEM_TEXTURE), + bvh_leaf_nodes(device, "__bvh_leaf_nodes", MEM_TEXTURE), + object_node(device, "__object_node", MEM_TEXTURE), + prim_tri_index(device, "__prim_tri_index", MEM_TEXTURE), + prim_tri_verts(device, "__prim_tri_verts", MEM_TEXTURE), + prim_type(device, "__prim_type", MEM_TEXTURE), + prim_visibility(device, "__prim_visibility", MEM_TEXTURE), + prim_index(device, "__prim_index", MEM_TEXTURE), + prim_object(device, "__prim_object", MEM_TEXTURE), + prim_time(device, "__prim_time", MEM_TEXTURE), + tri_shader(device, "__tri_shader", MEM_TEXTURE), + tri_vnormal(device, "__tri_vnormal", MEM_TEXTURE), + tri_vindex(device, "__tri_vindex", MEM_TEXTURE), + tri_patch(device, "__tri_patch", MEM_TEXTURE), + tri_patch_uv(device, "__tri_patch_uv", MEM_TEXTURE), + curves(device, "__curves", MEM_TEXTURE), + curve_keys(device, "__curve_keys", MEM_TEXTURE), + patches(device, "__patches", MEM_TEXTURE), + objects(device, "__objects", MEM_TEXTURE), + object_motion_pass(device, "__object_motion_pass", MEM_TEXTURE), + object_motion(device, "__object_motion", MEM_TEXTURE), + object_flag(device, "__object_flag", MEM_TEXTURE), + camera_motion(device, "__camera_motion", MEM_TEXTURE), + attributes_map(device, "__attributes_map", MEM_TEXTURE), + attributes_float(device, "__attributes_float", MEM_TEXTURE), + attributes_float2(device, "__attributes_float2", MEM_TEXTURE), + attributes_float3(device, "__attributes_float3", MEM_TEXTURE), + attributes_uchar4(device, "__attributes_uchar4", MEM_TEXTURE), + light_distribution(device, "__light_distribution", MEM_TEXTURE), + lights(device, "__lights", MEM_TEXTURE), + light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_TEXTURE), + light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_TEXTURE), + particles(device, "__particles", MEM_TEXTURE), + svm_nodes(device, "__svm_nodes", MEM_TEXTURE), + shaders(device, "__shaders", MEM_TEXTURE), + lookup_table(device, "__lookup_table", MEM_TEXTURE), + sobol_directions(device, "__sobol_directions", MEM_TEXTURE), + ies_lights(device, "__ies", MEM_TEXTURE) { - memset((void*)&data, 0, sizeof(data)); + memset((void *)&data, 0, sizeof(data)); } -Scene::Scene(const SceneParams& params_, Device *device) - : name("Scene"), - device(device), - dscene(device), - params(params_) +Scene::Scene(const SceneParams ¶ms_, Device *device) + : name("Scene"), device(device), dscene(device), params(params_) { - memset((void *)&dscene.data, 0, sizeof(dscene.data)); - - camera = new Camera(); - dicing_camera = new Camera(); - lookup_tables = new LookupTables(); - film = new Film(); - background = new Background(); - light_manager = new LightManager(); - mesh_manager = new MeshManager(); - object_manager = new ObjectManager(); - integrator = new Integrator(); - image_manager = new ImageManager(device->info); - particle_system_manager = new ParticleSystemManager(); - curve_system_manager = new CurveSystemManager(); - bake_manager = new BakeManager(); - - /* OSL only works on the CPU */ - if(device->info.has_osl) - shader_manager = ShaderManager::create(this, params.shadingsystem); - else - shader_manager = ShaderManager::create(this, SHADINGSYSTEM_SVM); + memset((void *)&dscene.data, 0, sizeof(dscene.data)); + + camera = new Camera(); + dicing_camera = new Camera(); + lookup_tables = new LookupTables(); + film = new Film(); + background = new Background(); + light_manager = new LightManager(); + mesh_manager = new MeshManager(); + object_manager = new ObjectManager(); + integrator = new Integrator(); + image_manager = new ImageManager(device->info); + particle_system_manager = new ParticleSystemManager(); + curve_system_manager = new CurveSystemManager(); + bake_manager = new BakeManager(); + + /* OSL only works on the CPU */ + if (device->info.has_osl) + shader_manager = ShaderManager::create(this, params.shadingsystem); + else + shader_manager = ShaderManager::create(this, SHADINGSYSTEM_SVM); } Scene::~Scene() { - free_memory(true); + free_memory(true); } void Scene::free_memory(bool final) { - foreach(Shader *s, shaders) - delete s; - foreach(Mesh *m, meshes) - delete m; - foreach(Object *o, objects) - delete o; - foreach(Light *l, lights) - delete l; - foreach(ParticleSystem *p, particle_systems) - delete p; - - shaders.clear(); - meshes.clear(); - objects.clear(); - lights.clear(); - particle_systems.clear(); - - if(device) { - camera->device_free(device, &dscene, this); - film->device_free(device, &dscene, this); - background->device_free(device, &dscene); - integrator->device_free(device, &dscene); - - object_manager->device_free(device, &dscene); - mesh_manager->device_free(device, &dscene); - shader_manager->device_free(device, &dscene, this); - light_manager->device_free(device, &dscene); - - particle_system_manager->device_free(device, &dscene); - curve_system_manager->device_free(device, &dscene); - - bake_manager->device_free(device, &dscene); - - if(!params.persistent_data || final) - image_manager->device_free(device); - else - image_manager->device_free_builtin(device); - - lookup_tables->device_free(device, &dscene); - } - - if(final) { - delete lookup_tables; - delete camera; - delete dicing_camera; - delete film; - delete background; - delete integrator; - delete object_manager; - delete mesh_manager; - delete shader_manager; - delete light_manager; - delete particle_system_manager; - delete curve_system_manager; - delete image_manager; - delete bake_manager; - } + foreach (Shader *s, shaders) + delete s; + foreach (Mesh *m, meshes) + delete m; + foreach (Object *o, objects) + delete o; + foreach (Light *l, lights) + delete l; + foreach (ParticleSystem *p, particle_systems) + delete p; + + shaders.clear(); + meshes.clear(); + objects.clear(); + lights.clear(); + particle_systems.clear(); + + if (device) { + camera->device_free(device, &dscene, this); + film->device_free(device, &dscene, this); + background->device_free(device, &dscene); + integrator->device_free(device, &dscene); + + object_manager->device_free(device, &dscene); + mesh_manager->device_free(device, &dscene); + shader_manager->device_free(device, &dscene, this); + light_manager->device_free(device, &dscene); + + particle_system_manager->device_free(device, &dscene); + curve_system_manager->device_free(device, &dscene); + + bake_manager->device_free(device, &dscene); + + if (!params.persistent_data || final) + image_manager->device_free(device); + else + image_manager->device_free_builtin(device); + + lookup_tables->device_free(device, &dscene); + } + + if (final) { + delete lookup_tables; + delete camera; + delete dicing_camera; + delete film; + delete background; + delete integrator; + delete object_manager; + delete mesh_manager; + delete shader_manager; + delete light_manager; + delete particle_system_manager; + delete curve_system_manager; + delete image_manager; + delete bake_manager; + } } -void Scene::device_update(Device *device_, Progress& progress) +void Scene::device_update(Device *device_, Progress &progress) { - if(!device) - device = device_; + if (!device) + device = device_; - bool print_stats = need_data_update(); + bool print_stats = need_data_update(); - /* The order of updates is important, because there's dependencies between - * the different managers, using data computed by previous managers. - * - * - Image manager uploads images used by shaders. - * - Camera may be used for adaptive subdivision. - * - Displacement shader must have all shader data available. - * - Light manager needs lookup tables and final mesh data to compute emission CDF. - * - Film needs light manager to run for use_light_visibility - * - Lookup tables are done a second time to handle film tables - */ + /* The order of updates is important, because there's dependencies between + * the different managers, using data computed by previous managers. + * + * - Image manager uploads images used by shaders. + * - Camera may be used for adaptive subdivision. + * - Displacement shader must have all shader data available. + * - Light manager needs lookup tables and final mesh data to compute emission CDF. + * - Film needs light manager to run for use_light_visibility + * - Lookup tables are done a second time to handle film tables + */ - progress.set_status("Updating Shaders"); - shader_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Shaders"); + shader_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Background"); - background->device_update(device, &dscene, this); + progress.set_status("Updating Background"); + background->device_update(device, &dscene, this); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Camera"); - camera->device_update(device, &dscene, this); + progress.set_status("Updating Camera"); + camera->device_update(device, &dscene, this); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - mesh_manager->device_update_preprocess(device, this, progress); + mesh_manager->device_update_preprocess(device, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Objects"); - object_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Objects"); + object_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Hair Systems"); - curve_system_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Hair Systems"); + curve_system_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Particle Systems"); - particle_system_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Particle Systems"); + particle_system_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Meshes"); - mesh_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Meshes"); + mesh_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Objects Flags"); - object_manager->device_update_flags(device, &dscene, this, progress); + progress.set_status("Updating Objects Flags"); + object_manager->device_update_flags(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Images"); - image_manager->device_update(device, this, progress); + progress.set_status("Updating Images"); + image_manager->device_update(device, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Camera Volume"); - camera->device_update_volume(device, &dscene, this); + progress.set_status("Updating Camera Volume"); + camera->device_update_volume(device, &dscene, this); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Lookup Tables"); - lookup_tables->device_update(device, &dscene); + progress.set_status("Updating Lookup Tables"); + lookup_tables->device_update(device, &dscene); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Lights"); - light_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Lights"); + light_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Integrator"); - integrator->device_update(device, &dscene, this); + progress.set_status("Updating Integrator"); + integrator->device_update(device, &dscene, this); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Film"); - film->device_update(device, &dscene, this); + progress.set_status("Updating Film"); + film->device_update(device, &dscene, this); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Lookup Tables"); - lookup_tables->device_update(device, &dscene); + progress.set_status("Updating Lookup Tables"); + lookup_tables->device_update(device, &dscene); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - progress.set_status("Updating Baking"); - bake_manager->device_update(device, &dscene, this, progress); + progress.set_status("Updating Baking"); + bake_manager->device_update(device, &dscene, this, progress); - if(progress.get_cancel() || device->have_error()) return; + if (progress.get_cancel() || device->have_error()) + return; - if(device->have_error() == false) { - progress.set_status("Updating Device", "Writing constant memory"); - device->const_copy_to("__data", &dscene.data, sizeof(dscene.data)); - } + if (device->have_error() == false) { + progress.set_status("Updating Device", "Writing constant memory"); + device->const_copy_to("__data", &dscene.data, sizeof(dscene.data)); + } - if(print_stats) { - size_t mem_used = util_guarded_get_mem_used(); - size_t mem_peak = util_guarded_get_mem_peak(); + if (print_stats) { + size_t mem_used = util_guarded_get_mem_used(); + size_t mem_peak = util_guarded_get_mem_peak(); - VLOG(1) << "System memory statistics after full device sync:\n" - << " Usage: " << string_human_readable_number(mem_used) - << " (" << string_human_readable_size(mem_used) << ")\n" - << " Peak: " << string_human_readable_number(mem_peak) - << " (" << string_human_readable_size(mem_peak) << ")"; - } + VLOG(1) << "System memory statistics after full device sync:\n" + << " Usage: " << string_human_readable_number(mem_used) << " (" + << string_human_readable_size(mem_used) << ")\n" + << " Peak: " << string_human_readable_number(mem_peak) << " (" + << string_human_readable_size(mem_peak) << ")"; + } } Scene::MotionType Scene::need_motion() { - if(integrator->motion_blur) - return MOTION_BLUR; - else if(Pass::contains(film->passes, PASS_MOTION)) - return MOTION_PASS; - else - return MOTION_NONE; + if (integrator->motion_blur) + return MOTION_BLUR; + else if (Pass::contains(film->passes, PASS_MOTION)) + return MOTION_PASS; + else + return MOTION_NONE; } float Scene::motion_shutter_time() { - if(need_motion() == Scene::MOTION_PASS) - return 2.0f; - else - return camera->shuttertime; + if (need_motion() == Scene::MOTION_PASS) + return 2.0f; + else + return camera->shuttertime; } bool Scene::need_global_attribute(AttributeStandard std) { - if(std == ATTR_STD_UV) - return Pass::contains(film->passes, PASS_UV); - else if(std == ATTR_STD_MOTION_VERTEX_POSITION) - return need_motion() != MOTION_NONE; - else if(std == ATTR_STD_MOTION_VERTEX_NORMAL) - return need_motion() == MOTION_BLUR; - - return false; + if (std == ATTR_STD_UV) + return Pass::contains(film->passes, PASS_UV); + else if (std == ATTR_STD_MOTION_VERTEX_POSITION) + return need_motion() != MOTION_NONE; + else if (std == ATTR_STD_MOTION_VERTEX_NORMAL) + return need_motion() == MOTION_BLUR; + + return false; } -void Scene::need_global_attributes(AttributeRequestSet& attributes) +void Scene::need_global_attributes(AttributeRequestSet &attributes) { - for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) - if(need_global_attribute((AttributeStandard)std)) - attributes.add((AttributeStandard)std); + for (int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) + if (need_global_attribute((AttributeStandard)std)) + attributes.add((AttributeStandard)std); } bool Scene::need_update() { - return (need_reset() || film->need_update); + return (need_reset() || film->need_update); } bool Scene::need_data_update() { - return (background->need_update - || image_manager->need_update - || object_manager->need_update - || mesh_manager->need_update - || light_manager->need_update - || lookup_tables->need_update - || integrator->need_update - || shader_manager->need_update - || particle_system_manager->need_update - || curve_system_manager->need_update - || bake_manager->need_update - || film->need_update); + return (background->need_update || image_manager->need_update || object_manager->need_update || + mesh_manager->need_update || light_manager->need_update || lookup_tables->need_update || + integrator->need_update || shader_manager->need_update || + particle_system_manager->need_update || curve_system_manager->need_update || + bake_manager->need_update || film->need_update); } bool Scene::need_reset() { - return need_data_update() || camera->need_update; + return need_data_update() || camera->need_update; } void Scene::reset() { - shader_manager->reset(this); - shader_manager->add_default(this); - - /* ensure all objects are updated */ - camera->tag_update(); - dicing_camera->tag_update(); - film->tag_update(this); - background->tag_update(this); - integrator->tag_update(this); - object_manager->tag_update(this); - mesh_manager->tag_update(this); - light_manager->tag_update(this); - particle_system_manager->tag_update(this); - curve_system_manager->tag_update(this); + shader_manager->reset(this); + shader_manager->add_default(this); + + /* ensure all objects are updated */ + camera->tag_update(); + dicing_camera->tag_update(); + film->tag_update(this); + background->tag_update(this); + integrator->tag_update(this); + object_manager->tag_update(this); + mesh_manager->tag_update(this); + light_manager->tag_update(this); + particle_system_manager->tag_update(this); + curve_system_manager->tag_update(this); } void Scene::device_free() { - free_memory(false); + free_memory(false); } void Scene::collect_statistics(RenderStats *stats) { - mesh_manager->collect_statistics(this, stats); - image_manager->collect_statistics(stats); + mesh_manager->collect_statistics(this, stats); + image_manager->collect_statistics(stats); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index e43800fe5c4..45997bccf5d 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -61,215 +61,215 @@ class RenderStats; /* Scene Device Data */ class DeviceScene { -public: - /* BVH */ - device_vector<int4> bvh_nodes; - device_vector<int4> bvh_leaf_nodes; - device_vector<int> object_node; - device_vector<uint> prim_tri_index; - device_vector<float4> prim_tri_verts; - device_vector<int> prim_type; - device_vector<uint> prim_visibility; - device_vector<int> prim_index; - device_vector<int> prim_object; - device_vector<float2> prim_time; - - /* mesh */ - device_vector<uint> tri_shader; - device_vector<float4> tri_vnormal; - device_vector<uint4> tri_vindex; - device_vector<uint> tri_patch; - device_vector<float2> tri_patch_uv; - - device_vector<float4> curves; - device_vector<float4> curve_keys; - - device_vector<uint> patches; - - /* objects */ - device_vector<KernelObject> objects; - device_vector<Transform> object_motion_pass; - device_vector<DecomposedTransform> object_motion; - device_vector<uint> object_flag; - - /* cameras */ - device_vector<DecomposedTransform> camera_motion; - - /* attributes */ - device_vector<uint4> attributes_map; - device_vector<float> attributes_float; - device_vector<float2> attributes_float2; - device_vector<float4> attributes_float3; - device_vector<uchar4> attributes_uchar4; - - /* lights */ - device_vector<KernelLightDistribution> light_distribution; - device_vector<KernelLight> lights; - device_vector<float2> light_background_marginal_cdf; - device_vector<float2> light_background_conditional_cdf; - - /* particles */ - device_vector<KernelParticle> particles; - - /* shaders */ - device_vector<int4> svm_nodes; - device_vector<KernelShader> shaders; - - /* lookup tables */ - device_vector<float> lookup_table; - - /* integrator */ - device_vector<uint> sobol_directions; - - /* ies lights */ - device_vector<float> ies_lights; - - KernelData data; - - DeviceScene(Device *device); + public: + /* BVH */ + device_vector<int4> bvh_nodes; + device_vector<int4> bvh_leaf_nodes; + device_vector<int> object_node; + device_vector<uint> prim_tri_index; + device_vector<float4> prim_tri_verts; + device_vector<int> prim_type; + device_vector<uint> prim_visibility; + device_vector<int> prim_index; + device_vector<int> prim_object; + device_vector<float2> prim_time; + + /* mesh */ + device_vector<uint> tri_shader; + device_vector<float4> tri_vnormal; + device_vector<uint4> tri_vindex; + device_vector<uint> tri_patch; + device_vector<float2> tri_patch_uv; + + device_vector<float4> curves; + device_vector<float4> curve_keys; + + device_vector<uint> patches; + + /* objects */ + device_vector<KernelObject> objects; + device_vector<Transform> object_motion_pass; + device_vector<DecomposedTransform> object_motion; + device_vector<uint> object_flag; + + /* cameras */ + device_vector<DecomposedTransform> camera_motion; + + /* attributes */ + device_vector<uint4> attributes_map; + device_vector<float> attributes_float; + device_vector<float2> attributes_float2; + device_vector<float4> attributes_float3; + device_vector<uchar4> attributes_uchar4; + + /* lights */ + device_vector<KernelLightDistribution> light_distribution; + device_vector<KernelLight> lights; + device_vector<float2> light_background_marginal_cdf; + device_vector<float2> light_background_conditional_cdf; + + /* particles */ + device_vector<KernelParticle> particles; + + /* shaders */ + device_vector<int4> svm_nodes; + device_vector<KernelShader> shaders; + + /* lookup tables */ + device_vector<float> lookup_table; + + /* integrator */ + device_vector<uint> sobol_directions; + + /* ies lights */ + device_vector<float> ies_lights; + + KernelData data; + + DeviceScene(Device *device); }; /* Scene Parameters */ class SceneParams { -public: - /* Type of BVH, in terms whether it is supported dynamic updates of meshes - * or whether modifying geometry requires full BVH rebuild. - */ - enum BVHType { - /* BVH supports dynamic updates of geometry. - * - * Faster for updating BVH tree when doing modifications in viewport, - * but slower for rendering. - */ - BVH_DYNAMIC = 0, - /* BVH tree is calculated for specific scene, updates in geometry - * requires full tree rebuild. - * - * Slower to update BVH tree when modifying objects in viewport, also - * slower to build final BVH tree but gives best possible render speed. - */ - BVH_STATIC = 1, - - BVH_NUM_TYPES, - }; - - ShadingSystem shadingsystem; - - /* Requested BVH layout. - * - * If it's not supported by the device, the widest one from supported ones - * will be used, but BVH wider than this one will never be used. - */ - BVHLayout bvh_layout; - - BVHType bvh_type; - bool use_bvh_spatial_split; - bool use_bvh_unaligned_nodes; - int num_bvh_time_steps; - bool persistent_data; - int texture_limit; - - SceneParams() - { - shadingsystem = SHADINGSYSTEM_SVM; - bvh_layout = BVH_LAYOUT_BVH2; - bvh_type = BVH_DYNAMIC; - use_bvh_spatial_split = false; - use_bvh_unaligned_nodes = true; - num_bvh_time_steps = 0; - persistent_data = false; - texture_limit = 0; - } - - bool modified(const SceneParams& params) - { return !(shadingsystem == params.shadingsystem - && bvh_layout == params.bvh_layout - && bvh_type == params.bvh_type - && use_bvh_spatial_split == params.use_bvh_spatial_split - && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes - && num_bvh_time_steps == params.num_bvh_time_steps - && persistent_data == params.persistent_data - && texture_limit == params.texture_limit); } + public: + /* Type of BVH, in terms whether it is supported dynamic updates of meshes + * or whether modifying geometry requires full BVH rebuild. + */ + enum BVHType { + /* BVH supports dynamic updates of geometry. + * + * Faster for updating BVH tree when doing modifications in viewport, + * but slower for rendering. + */ + BVH_DYNAMIC = 0, + /* BVH tree is calculated for specific scene, updates in geometry + * requires full tree rebuild. + * + * Slower to update BVH tree when modifying objects in viewport, also + * slower to build final BVH tree but gives best possible render speed. + */ + BVH_STATIC = 1, + + BVH_NUM_TYPES, + }; + + ShadingSystem shadingsystem; + + /* Requested BVH layout. + * + * If it's not supported by the device, the widest one from supported ones + * will be used, but BVH wider than this one will never be used. + */ + BVHLayout bvh_layout; + + BVHType bvh_type; + bool use_bvh_spatial_split; + bool use_bvh_unaligned_nodes; + int num_bvh_time_steps; + bool persistent_data; + int texture_limit; + + SceneParams() + { + shadingsystem = SHADINGSYSTEM_SVM; + bvh_layout = BVH_LAYOUT_BVH2; + bvh_type = BVH_DYNAMIC; + use_bvh_spatial_split = false; + use_bvh_unaligned_nodes = true; + num_bvh_time_steps = 0; + persistent_data = false; + texture_limit = 0; + } + + bool modified(const SceneParams ¶ms) + { + return !(shadingsystem == params.shadingsystem && bvh_layout == params.bvh_layout && + bvh_type == params.bvh_type && + use_bvh_spatial_split == params.use_bvh_spatial_split && + use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && + num_bvh_time_steps == params.num_bvh_time_steps && + persistent_data == params.persistent_data && texture_limit == params.texture_limit); + } }; /* Scene */ class Scene { -public: - /* Optional name. Is used for logging and reporting. */ - string name; - - /* data */ - Camera *camera; - Camera *dicing_camera; - LookupTables *lookup_tables; - Film *film; - Background *background; - Integrator *integrator; - - /* data lists */ - vector<Object*> objects; - vector<Mesh*> meshes; - vector<Shader*> shaders; - vector<Light*> lights; - vector<ParticleSystem*> particle_systems; - - /* data managers */ - ImageManager *image_manager; - LightManager *light_manager; - ShaderManager *shader_manager; - MeshManager *mesh_manager; - ObjectManager *object_manager; - ParticleSystemManager *particle_system_manager; - CurveSystemManager *curve_system_manager; - BakeManager *bake_manager; - - /* default shaders */ - Shader *default_surface; - Shader *default_light; - Shader *default_background; - Shader *default_empty; - - /* device */ - Device *device; - DeviceScene dscene; - - /* parameters */ - SceneParams params; - - /* mutex must be locked manually by callers */ - thread_mutex mutex; - - Scene(const SceneParams& params, Device *device); - ~Scene(); - - void device_update(Device *device, Progress& progress); - - bool need_global_attribute(AttributeStandard std); - void need_global_attributes(AttributeRequestSet& attributes); - - enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; - MotionType need_motion(); - float motion_shutter_time(); - - bool need_update(); - bool need_reset(); - - void reset(); - void device_free(); - - void collect_statistics(RenderStats *stats); - -protected: - /* Check if some heavy data worth logging was updated. - * Mainly used to suppress extra annoying logging. - */ - bool need_data_update(); - - void free_memory(bool final); + public: + /* Optional name. Is used for logging and reporting. */ + string name; + + /* data */ + Camera *camera; + Camera *dicing_camera; + LookupTables *lookup_tables; + Film *film; + Background *background; + Integrator *integrator; + + /* data lists */ + vector<Object *> objects; + vector<Mesh *> meshes; + vector<Shader *> shaders; + vector<Light *> lights; + vector<ParticleSystem *> particle_systems; + + /* data managers */ + ImageManager *image_manager; + LightManager *light_manager; + ShaderManager *shader_manager; + MeshManager *mesh_manager; + ObjectManager *object_manager; + ParticleSystemManager *particle_system_manager; + CurveSystemManager *curve_system_manager; + BakeManager *bake_manager; + + /* default shaders */ + Shader *default_surface; + Shader *default_light; + Shader *default_background; + Shader *default_empty; + + /* device */ + Device *device; + DeviceScene dscene; + + /* parameters */ + SceneParams params; + + /* mutex must be locked manually by callers */ + thread_mutex mutex; + + Scene(const SceneParams ¶ms, Device *device); + ~Scene(); + + void device_update(Device *device, Progress &progress); + + bool need_global_attribute(AttributeStandard std); + void need_global_attributes(AttributeRequestSet &attributes); + + enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; + MotionType need_motion(); + float motion_shutter_time(); + + bool need_update(); + bool need_reset(); + + void reset(); + void device_free(); + + void collect_statistics(RenderStats *stats); + + protected: + /* Check if some heavy data worth logging was updated. + * Mainly used to suppress extra annoying logging. + */ + bool need_data_update(); + + void free_memory(bool final); }; CCL_NAMESPACE_END -#endif /* __SCENE_H__ */ +#endif /* __SCENE_H__ */ diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index e88d960d9d2..29eb779a7d6 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -43,1121 +43,1122 @@ CCL_NAMESPACE_BEGIN * progressive refine and viewport rendering does requires tiles to * always be allocated for the same device */ -Session::Session(const SessionParams& params_) -: params(params_), - tile_manager(params.progressive, params.samples, params.tile_size, params.start_resolution, - params.background == false || params.progressive_refine, params.background, params.tile_order, - max(params.device.multi_devices.size(), 1), params.pixel_size), - stats(), - profiler() +Session::Session(const SessionParams ¶ms_) + : params(params_), + tile_manager(params.progressive, + params.samples, + params.tile_size, + params.start_resolution, + params.background == false || params.progressive_refine, + params.background, + params.tile_order, + max(params.device.multi_devices.size(), 1), + params.pixel_size), + stats(), + profiler() { - device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background); + device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background); - TaskScheduler::init(params.threads); + TaskScheduler::init(params.threads); - device = Device::create(params.device, stats, profiler, params.background); + device = Device::create(params.device, stats, profiler, params.background); - if(params.background && !params.write_render_cb) { - buffers = NULL; - display = NULL; - } - else { - buffers = new RenderBuffers(device); - display = new DisplayBuffer(device, params.display_buffer_linear); - } + if (params.background && !params.write_render_cb) { + buffers = NULL; + display = NULL; + } + else { + buffers = new RenderBuffers(device); + display = new DisplayBuffer(device, params.display_buffer_linear); + } - session_thread = NULL; - scene = NULL; + session_thread = NULL; + scene = NULL; - reset_time = 0.0; - last_update_time = 0.0; + reset_time = 0.0; + last_update_time = 0.0; - delayed_reset.do_reset = false; - delayed_reset.samples = 0; + delayed_reset.do_reset = false; + delayed_reset.samples = 0; - display_outdated = false; - gpu_draw_ready = false; - gpu_need_tonemap = false; - pause = false; - kernels_loaded = false; + display_outdated = false; + gpu_draw_ready = false; + gpu_need_tonemap = false; + pause = false; + kernels_loaded = false; - /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */ - max_closure_global = 1; + /* TODO(sergey): Check if it's indeed optimal value for the split kernel. */ + max_closure_global = 1; } Session::~Session() { - if(session_thread) { - /* wait for session thread to end */ - progress.set_cancel("Exiting"); + if (session_thread) { + /* wait for session thread to end */ + progress.set_cancel("Exiting"); - gpu_need_tonemap = false; - gpu_need_tonemap_cond.notify_all(); + gpu_need_tonemap = false; + gpu_need_tonemap_cond.notify_all(); - { - thread_scoped_lock pause_lock(pause_mutex); - pause = false; - } - pause_cond.notify_all(); + { + thread_scoped_lock pause_lock(pause_mutex); + pause = false; + } + pause_cond.notify_all(); - wait(); - } + wait(); + } - if(params.write_render_cb) { - /* tonemap and write out image if requested */ - delete display; + if (params.write_render_cb) { + /* tonemap and write out image if requested */ + delete display; - display = new DisplayBuffer(device, false); - display->reset(buffers->params); - tonemap(params.samples); + display = new DisplayBuffer(device, false); + display->reset(buffers->params); + tonemap(params.samples); - int w = display->draw_width; - int h = display->draw_height; - uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h); - params.write_render_cb((uchar*)pixels, w, h, 4); - } + int w = display->draw_width; + int h = display->draw_height; + uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h); + params.write_render_cb((uchar *)pixels, w, h, 4); + } - /* clean up */ - tile_manager.device_free(); + /* clean up */ + tile_manager.device_free(); - delete buffers; - delete display; - delete scene; - delete device; + delete buffers; + delete display; + delete scene; + delete device; - TaskScheduler::exit(); + TaskScheduler::exit(); } void Session::start() { - if (!session_thread) { - session_thread = new thread(function_bind(&Session::run, this)); - } + if (!session_thread) { + session_thread = new thread(function_bind(&Session::run, this)); + } } bool Session::ready_to_reset() { - double dt = time_dt() - reset_time; + double dt = time_dt() - reset_time; - if(!display_outdated) - return (dt > params.reset_timeout); - else - return (dt > params.cancel_timeout); + if (!display_outdated) + return (dt > params.reset_timeout); + else + return (dt > params.cancel_timeout); } /* GPU Session */ -void Session::reset_gpu(BufferParams& buffer_params, int samples) +void Session::reset_gpu(BufferParams &buffer_params, int samples) { - thread_scoped_lock pause_lock(pause_mutex); + thread_scoped_lock pause_lock(pause_mutex); - /* block for buffer access and reset immediately. we can't do this - * in the thread, because we need to allocate an OpenGL buffer, and - * that only works in the main thread */ - thread_scoped_lock display_lock(display_mutex); - thread_scoped_lock buffers_lock(buffers_mutex); + /* block for buffer access and reset immediately. we can't do this + * in the thread, because we need to allocate an OpenGL buffer, and + * that only works in the main thread */ + thread_scoped_lock display_lock(display_mutex); + thread_scoped_lock buffers_lock(buffers_mutex); - display_outdated = true; - reset_time = time_dt(); + display_outdated = true; + reset_time = time_dt(); - reset_(buffer_params, samples); + reset_(buffer_params, samples); - gpu_need_tonemap = false; - gpu_need_tonemap_cond.notify_all(); + gpu_need_tonemap = false; + gpu_need_tonemap_cond.notify_all(); - pause_cond.notify_all(); + pause_cond.notify_all(); } -bool Session::draw_gpu(BufferParams& buffer_params, DeviceDrawParams& draw_params) +bool Session::draw_gpu(BufferParams &buffer_params, DeviceDrawParams &draw_params) { - /* block for buffer access */ - thread_scoped_lock display_lock(display_mutex); - - /* first check we already rendered something */ - if(gpu_draw_ready) { - /* then verify the buffers have the expected size, so we don't - * draw previous results in a resized window */ - if(!buffer_params.modified(display->params)) { - /* for CUDA we need to do tonemapping still, since we can - * only access GL buffers from the main thread */ - if(gpu_need_tonemap) { - thread_scoped_lock buffers_lock(buffers_mutex); - tonemap(tile_manager.state.sample); - gpu_need_tonemap = false; - gpu_need_tonemap_cond.notify_all(); - } - - display->draw(device, draw_params); - - if(display_outdated && (time_dt() - reset_time) > params.text_timeout) - return false; - - return true; - } - } - - return false; + /* block for buffer access */ + thread_scoped_lock display_lock(display_mutex); + + /* first check we already rendered something */ + if (gpu_draw_ready) { + /* then verify the buffers have the expected size, so we don't + * draw previous results in a resized window */ + if (!buffer_params.modified(display->params)) { + /* for CUDA we need to do tonemapping still, since we can + * only access GL buffers from the main thread */ + if (gpu_need_tonemap) { + thread_scoped_lock buffers_lock(buffers_mutex); + tonemap(tile_manager.state.sample); + gpu_need_tonemap = false; + gpu_need_tonemap_cond.notify_all(); + } + + display->draw(device, draw_params); + + if (display_outdated && (time_dt() - reset_time) > params.text_timeout) + return false; + + return true; + } + } + + return false; } void Session::run_gpu() { - bool tiles_written = false; - - reset_time = time_dt(); - last_update_time = time_dt(); - - progress.set_render_start_time(); - - while(!progress.get_cancel()) { - /* advance to next tile */ - bool no_tiles = !tile_manager.next(); - - DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN; - if (no_tiles) { - kernel_state = device->get_active_kernel_switch_state(); - } - - if(params.background) { - /* if no work left and in background mode, we can stop immediately */ - if(no_tiles) { - progress.set_status("Finished"); - break; - } - } - - /* Don't go in pause mode when image was rendered with preview kernels - * When feature kernels become available the session will be resetted. */ - else if (no_tiles && kernel_state == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { - time_sleep(0.1); - } - else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) { - reset_gpu(tile_manager.params, params.samples); - } - - else { - /* if in interactive mode, and we are either paused or done for now, - * wait for pause condition notify to wake up again */ - thread_scoped_lock pause_lock(pause_mutex); - - if(!pause && !tile_manager.done()) { - /* reset could have happened after no_tiles was set, before this lock. - * in this case we shall not wait for pause condition - */ - } - else if(pause || no_tiles) { - update_status_time(pause, no_tiles); - - while(1) { - scoped_timer pause_timer; - pause_cond.wait(pause_lock); - if(pause) { - progress.add_skip_time(pause_timer, params.background); - } - - update_status_time(pause, no_tiles); - progress.set_update(); - - if(!pause) - break; - } - } - - if(progress.get_cancel()) - break; - } - - if(!no_tiles) { - /* update scene */ - scoped_timer update_timer; - if(update_scene()) { - profiler.reset(scene->shaders.size(), scene->objects.size()); - } - progress.add_skip_time(update_timer, params.background); - - if(!device->error_message().empty()) - progress.set_error(device->error_message()); - - if(progress.get_cancel()) - break; - } - - if(!no_tiles) { - /* buffers mutex is locked entirely while rendering each - * sample, and released/reacquired on each iteration to allow - * reset and draw in between */ - thread_scoped_lock buffers_lock(buffers_mutex); - - /* update status and timing */ - update_status_time(); - - /* render */ - render(); - - device->task_wait(); - - if(!device->error_message().empty()) - progress.set_cancel(device->error_message()); - - /* update status and timing */ - update_status_time(); - - gpu_need_tonemap = true; - gpu_draw_ready = true; - progress.set_update(); - - /* wait for tonemap */ - if(!params.background) { - while(gpu_need_tonemap) { - if(progress.get_cancel()) - break; - - gpu_need_tonemap_cond.wait(buffers_lock); - } - } - - if(!device->error_message().empty()) - progress.set_error(device->error_message()); - - tiles_written = update_progressive_refine(progress.get_cancel()); - - if(progress.get_cancel()) - break; - } - } - - if(!tiles_written) - update_progressive_refine(true); + bool tiles_written = false; + + reset_time = time_dt(); + last_update_time = time_dt(); + + progress.set_render_start_time(); + + while (!progress.get_cancel()) { + /* advance to next tile */ + bool no_tiles = !tile_manager.next(); + + DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN; + if (no_tiles) { + kernel_state = device->get_active_kernel_switch_state(); + } + + if (params.background) { + /* if no work left and in background mode, we can stop immediately */ + if (no_tiles) { + progress.set_status("Finished"); + break; + } + } + + /* Don't go in pause mode when image was rendered with preview kernels + * When feature kernels become available the session will be resetted. */ + else if (no_tiles && kernel_state == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { + time_sleep(0.1); + } + else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) { + reset_gpu(tile_manager.params, params.samples); + } + + else { + /* if in interactive mode, and we are either paused or done for now, + * wait for pause condition notify to wake up again */ + thread_scoped_lock pause_lock(pause_mutex); + + if (!pause && !tile_manager.done()) { + /* reset could have happened after no_tiles was set, before this lock. + * in this case we shall not wait for pause condition + */ + } + else if (pause || no_tiles) { + update_status_time(pause, no_tiles); + + while (1) { + scoped_timer pause_timer; + pause_cond.wait(pause_lock); + if (pause) { + progress.add_skip_time(pause_timer, params.background); + } + + update_status_time(pause, no_tiles); + progress.set_update(); + + if (!pause) + break; + } + } + + if (progress.get_cancel()) + break; + } + + if (!no_tiles) { + /* update scene */ + scoped_timer update_timer; + if (update_scene()) { + profiler.reset(scene->shaders.size(), scene->objects.size()); + } + progress.add_skip_time(update_timer, params.background); + + if (!device->error_message().empty()) + progress.set_error(device->error_message()); + + if (progress.get_cancel()) + break; + } + + if (!no_tiles) { + /* buffers mutex is locked entirely while rendering each + * sample, and released/reacquired on each iteration to allow + * reset and draw in between */ + thread_scoped_lock buffers_lock(buffers_mutex); + + /* update status and timing */ + update_status_time(); + + /* render */ + render(); + + device->task_wait(); + + if (!device->error_message().empty()) + progress.set_cancel(device->error_message()); + + /* update status and timing */ + update_status_time(); + + gpu_need_tonemap = true; + gpu_draw_ready = true; + progress.set_update(); + + /* wait for tonemap */ + if (!params.background) { + while (gpu_need_tonemap) { + if (progress.get_cancel()) + break; + + gpu_need_tonemap_cond.wait(buffers_lock); + } + } + + if (!device->error_message().empty()) + progress.set_error(device->error_message()); + + tiles_written = update_progressive_refine(progress.get_cancel()); + + if (progress.get_cancel()) + break; + } + } + + if (!tiles_written) + update_progressive_refine(true); } /* CPU Session */ -void Session::reset_cpu(BufferParams& buffer_params, int samples) +void Session::reset_cpu(BufferParams &buffer_params, int samples) { - thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock pause_lock(pause_mutex); + thread_scoped_lock reset_lock(delayed_reset.mutex); + thread_scoped_lock pause_lock(pause_mutex); - display_outdated = true; - reset_time = time_dt(); + display_outdated = true; + reset_time = time_dt(); - delayed_reset.params = buffer_params; - delayed_reset.samples = samples; - delayed_reset.do_reset = true; - device->task_cancel(); + delayed_reset.params = buffer_params; + delayed_reset.samples = samples; + delayed_reset.do_reset = true; + device->task_cancel(); - pause_cond.notify_all(); + pause_cond.notify_all(); } -bool Session::draw_cpu(BufferParams& buffer_params, DeviceDrawParams& draw_params) +bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_params) { - thread_scoped_lock display_lock(display_mutex); + thread_scoped_lock display_lock(display_mutex); - /* first check we already rendered something */ - if(display->draw_ready()) { - /* then verify the buffers have the expected size, so we don't - * draw previous results in a resized window */ - if(!buffer_params.modified(display->params)) { - display->draw(device, draw_params); + /* first check we already rendered something */ + if (display->draw_ready()) { + /* then verify the buffers have the expected size, so we don't + * draw previous results in a resized window */ + if (!buffer_params.modified(display->params)) { + display->draw(device, draw_params); - if(display_outdated && (time_dt() - reset_time) > params.text_timeout) - return false; + if (display_outdated && (time_dt() - reset_time) > params.text_timeout) + return false; - return true; - } - } + return true; + } + } - return false; + return false; } -bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) +bool Session::acquire_tile(Device *tile_device, RenderTile &rtile) { - if(progress.get_cancel()) { - if(params.progressive_refine == false) { - /* for progressive refine current sample should be finished for all tiles */ - return false; - } - } - - thread_scoped_lock tile_lock(tile_mutex); - - /* get next tile from manager */ - Tile *tile; - int device_num = device->device_number(tile_device); - - if(!tile_manager.next_tile(tile, device_num)) - return false; - - /* fill render tile */ - rtile.x = tile_manager.state.buffer.full_x + tile->x; - rtile.y = tile_manager.state.buffer.full_y + tile->y; - rtile.w = tile->w; - rtile.h = tile->h; - rtile.start_sample = tile_manager.state.sample; - rtile.num_samples = tile_manager.state.num_samples; - rtile.resolution = tile_manager.state.resolution_divider; - rtile.tile_index = tile->index; - rtile.task = (tile->state == Tile::DENOISE)? RenderTile::DENOISE: RenderTile::PATH_TRACE; - - tile_lock.unlock(); - - /* in case of a permanent buffer, return it, otherwise we will allocate - * a new temporary buffer */ - if(buffers) { - tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); - - rtile.buffer = buffers->buffer.device_pointer; - rtile.buffers = buffers; - - device->map_tile(tile_device, rtile); - - return true; - } - - if(tile->buffers == NULL) { - /* fill buffer parameters */ - BufferParams buffer_params = tile_manager.params; - buffer_params.full_x = rtile.x; - buffer_params.full_y = rtile.y; - buffer_params.width = rtile.w; - buffer_params.height = rtile.h; - - /* allocate buffers */ - tile->buffers = new RenderBuffers(tile_device); - tile->buffers->reset(buffer_params); - } - - tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride); - - rtile.buffer = tile->buffers->buffer.device_pointer; - rtile.buffers = tile->buffers; - rtile.sample = tile_manager.state.sample; - - /* this will tag tile as IN PROGRESS in blender-side render pipeline, - * which is needed to highlight currently rendering tile before first - * sample was processed for it - */ - update_tile_sample(rtile); - - return true; + if (progress.get_cancel()) { + if (params.progressive_refine == false) { + /* for progressive refine current sample should be finished for all tiles */ + return false; + } + } + + thread_scoped_lock tile_lock(tile_mutex); + + /* get next tile from manager */ + Tile *tile; + int device_num = device->device_number(tile_device); + + if (!tile_manager.next_tile(tile, device_num)) + return false; + + /* fill render tile */ + rtile.x = tile_manager.state.buffer.full_x + tile->x; + rtile.y = tile_manager.state.buffer.full_y + tile->y; + rtile.w = tile->w; + rtile.h = tile->h; + rtile.start_sample = tile_manager.state.sample; + rtile.num_samples = tile_manager.state.num_samples; + rtile.resolution = tile_manager.state.resolution_divider; + rtile.tile_index = tile->index; + rtile.task = (tile->state == Tile::DENOISE) ? RenderTile::DENOISE : RenderTile::PATH_TRACE; + + tile_lock.unlock(); + + /* in case of a permanent buffer, return it, otherwise we will allocate + * a new temporary buffer */ + if (buffers) { + tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); + + rtile.buffer = buffers->buffer.device_pointer; + rtile.buffers = buffers; + + device->map_tile(tile_device, rtile); + + return true; + } + + if (tile->buffers == NULL) { + /* fill buffer parameters */ + BufferParams buffer_params = tile_manager.params; + buffer_params.full_x = rtile.x; + buffer_params.full_y = rtile.y; + buffer_params.width = rtile.w; + buffer_params.height = rtile.h; + + /* allocate buffers */ + tile->buffers = new RenderBuffers(tile_device); + tile->buffers->reset(buffer_params); + } + + tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride); + + rtile.buffer = tile->buffers->buffer.device_pointer; + rtile.buffers = tile->buffers; + rtile.sample = tile_manager.state.sample; + + /* this will tag tile as IN PROGRESS in blender-side render pipeline, + * which is needed to highlight currently rendering tile before first + * sample was processed for it + */ + update_tile_sample(rtile); + + return true; } -void Session::update_tile_sample(RenderTile& rtile) +void Session::update_tile_sample(RenderTile &rtile) { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex); - if(update_render_tile_cb) { - if(params.progressive_refine == false) { - /* todo: optimize this by making it thread safe and removing lock */ + if (update_render_tile_cb) { + if (params.progressive_refine == false) { + /* todo: optimize this by making it thread safe and removing lock */ - update_render_tile_cb(rtile, true); - } - } + update_render_tile_cb(rtile, true); + } + } - update_status_time(); + update_status_time(); } -void Session::release_tile(RenderTile& rtile) +void Session::release_tile(RenderTile &rtile) { - thread_scoped_lock tile_lock(tile_mutex); + thread_scoped_lock tile_lock(tile_mutex); - progress.add_finished_tile(rtile.task == RenderTile::DENOISE); + progress.add_finished_tile(rtile.task == RenderTile::DENOISE); - bool delete_tile; + bool delete_tile; - if(tile_manager.finish_tile(rtile.tile_index, delete_tile)) { - if(write_render_tile_cb && params.progressive_refine == false) { - write_render_tile_cb(rtile); - } + if (tile_manager.finish_tile(rtile.tile_index, delete_tile)) { + if (write_render_tile_cb && params.progressive_refine == false) { + write_render_tile_cb(rtile); + } - if(delete_tile) { - delete rtile.buffers; - tile_manager.state.tiles[rtile.tile_index].buffers = NULL; - } - } - else { - if(update_render_tile_cb && params.progressive_refine == false) { - update_render_tile_cb(rtile, false); - } - } + if (delete_tile) { + delete rtile.buffers; + tile_manager.state.tiles[rtile.tile_index].buffers = NULL; + } + } + else { + if (update_render_tile_cb && params.progressive_refine == false) { + update_render_tile_cb(rtile, false); + } + } - update_status_time(); + update_status_time(); } void Session::map_neighbor_tiles(RenderTile *tiles, Device *tile_device) { - thread_scoped_lock tile_lock(tile_mutex); - - int center_idx = tiles[4].tile_index; - assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE); - BufferParams buffer_params = tile_manager.params; - int4 image_region = make_int4(buffer_params.full_x, buffer_params.full_y, - buffer_params.full_x + buffer_params.width, buffer_params.full_y + buffer_params.height); - - for(int dy = -1, i = 0; dy <= 1; dy++) { - for(int dx = -1; dx <= 1; dx++, i++) { - int px = tiles[4].x + dx*params.tile_size.x; - int py = tiles[4].y + dy*params.tile_size.y; - if(px >= image_region.x && py >= image_region.y && - px < image_region.z && py < image_region.w) { - int tile_index = center_idx + dy*tile_manager.state.tile_stride + dx; - Tile *tile = &tile_manager.state.tiles[tile_index]; - assert(tile->buffers); - - tiles[i].buffer = tile->buffers->buffer.device_pointer; - tiles[i].x = tile_manager.state.buffer.full_x + tile->x; - tiles[i].y = tile_manager.state.buffer.full_y + tile->y; - tiles[i].w = tile->w; - tiles[i].h = tile->h; - tiles[i].buffers = tile->buffers; - - tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride); - } - else { - tiles[i].buffer = (device_ptr)NULL; - tiles[i].buffers = NULL; - tiles[i].x = clamp(px, image_region.x, image_region.z); - tiles[i].y = clamp(py, image_region.y, image_region.w); - tiles[i].w = tiles[i].h = 0; - } - } - } - - assert(tiles[4].buffers); - device->map_neighbor_tiles(tile_device, tiles); - - /* The denoised result is written back to the original tile. */ - tiles[9] = tiles[4]; + thread_scoped_lock tile_lock(tile_mutex); + + int center_idx = tiles[4].tile_index; + assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE); + BufferParams buffer_params = tile_manager.params; + int4 image_region = make_int4(buffer_params.full_x, + buffer_params.full_y, + buffer_params.full_x + buffer_params.width, + buffer_params.full_y + buffer_params.height); + + for (int dy = -1, i = 0; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++, i++) { + int px = tiles[4].x + dx * params.tile_size.x; + int py = tiles[4].y + dy * params.tile_size.y; + if (px >= image_region.x && py >= image_region.y && px < image_region.z && + py < image_region.w) { + int tile_index = center_idx + dy * tile_manager.state.tile_stride + dx; + Tile *tile = &tile_manager.state.tiles[tile_index]; + assert(tile->buffers); + + tiles[i].buffer = tile->buffers->buffer.device_pointer; + tiles[i].x = tile_manager.state.buffer.full_x + tile->x; + tiles[i].y = tile_manager.state.buffer.full_y + tile->y; + tiles[i].w = tile->w; + tiles[i].h = tile->h; + tiles[i].buffers = tile->buffers; + + tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride); + } + else { + tiles[i].buffer = (device_ptr)NULL; + tiles[i].buffers = NULL; + tiles[i].x = clamp(px, image_region.x, image_region.z); + tiles[i].y = clamp(py, image_region.y, image_region.w); + tiles[i].w = tiles[i].h = 0; + } + } + } + + assert(tiles[4].buffers); + device->map_neighbor_tiles(tile_device, tiles); + + /* The denoised result is written back to the original tile. */ + tiles[9] = tiles[4]; } void Session::unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device) { - thread_scoped_lock tile_lock(tile_mutex); - device->unmap_neighbor_tiles(tile_device, tiles); + thread_scoped_lock tile_lock(tile_mutex); + device->unmap_neighbor_tiles(tile_device, tiles); } void Session::run_cpu() { - bool tiles_written = false; - - last_update_time = time_dt(); - - { - /* reset once to start */ - thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock buffers_lock(buffers_mutex); - thread_scoped_lock display_lock(display_mutex); - - reset_(delayed_reset.params, delayed_reset.samples); - delayed_reset.do_reset = false; - } - - while(!progress.get_cancel()) { - /* advance to next tile */ - bool no_tiles = !tile_manager.next(); - bool need_tonemap = false; - - DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN; - if (no_tiles) { - kernel_state = device->get_active_kernel_switch_state(); - } - - if(params.background) { - /* if no work left and in background mode, we can stop immediately */ - if(no_tiles) { - progress.set_status("Finished"); - break; - } - } - - /* Don't go in pause mode when preview kernels are used - * When feature kernels become available the session will be resetted. */ - else if (no_tiles && kernel_state == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { - time_sleep(0.1); - } - else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) { - reset_cpu(tile_manager.params, params.samples); - } - - else { - /* if in interactive mode, and we are either paused or done for now, - * wait for pause condition notify to wake up again */ - thread_scoped_lock pause_lock(pause_mutex); - - if(!pause && delayed_reset.do_reset) { - /* reset once to start */ - thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock buffers_lock(buffers_mutex); - thread_scoped_lock display_lock(display_mutex); - - reset_(delayed_reset.params, delayed_reset.samples); - delayed_reset.do_reset = false; - } - else if(pause || no_tiles) { - update_status_time(pause, no_tiles); - - while(1) { - scoped_timer pause_timer; - pause_cond.wait(pause_lock); - if(pause) { - progress.add_skip_time(pause_timer, params.background); - } - - update_status_time(pause, no_tiles); - progress.set_update(); - - if(!pause) - break; - } - } - - if(progress.get_cancel()) - break; - } - - if(!no_tiles) { - /* buffers mutex is locked entirely while rendering each - * sample, and released/reacquired on each iteration to allow - * reset and draw in between */ - thread_scoped_lock buffers_lock(buffers_mutex); - - /* update scene */ - scoped_timer update_timer; - if(update_scene()) { - profiler.reset(scene->shaders.size(), scene->objects.size()); - } - progress.add_skip_time(update_timer, params.background); - - if(!device->error_message().empty()) - progress.set_error(device->error_message()); - - if(progress.get_cancel()) - break; - - /* update status and timing */ - update_status_time(); - - /* render */ - render(); - - /* update status and timing */ - update_status_time(); - - if(!params.background) - need_tonemap = true; - - if(!device->error_message().empty()) - progress.set_error(device->error_message()); - } - - device->task_wait(); - - { - thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock buffers_lock(buffers_mutex); - thread_scoped_lock display_lock(display_mutex); - - if(delayed_reset.do_reset) { - /* reset rendering if request from main thread */ - delayed_reset.do_reset = false; - reset_(delayed_reset.params, delayed_reset.samples); - } - else if(need_tonemap) { - /* tonemap only if we do not reset, we don't we don't - * want to show the result of an incomplete sample */ - tonemap(tile_manager.state.sample); - } - - if(!device->error_message().empty()) - progress.set_error(device->error_message()); - - tiles_written = update_progressive_refine(progress.get_cancel()); - } - - progress.set_update(); - } - - if(!tiles_written) - update_progressive_refine(true); + bool tiles_written = false; + + last_update_time = time_dt(); + + { + /* reset once to start */ + thread_scoped_lock reset_lock(delayed_reset.mutex); + thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock display_lock(display_mutex); + + reset_(delayed_reset.params, delayed_reset.samples); + delayed_reset.do_reset = false; + } + + while (!progress.get_cancel()) { + /* advance to next tile */ + bool no_tiles = !tile_manager.next(); + bool need_tonemap = false; + + DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN; + if (no_tiles) { + kernel_state = device->get_active_kernel_switch_state(); + } + + if (params.background) { + /* if no work left and in background mode, we can stop immediately */ + if (no_tiles) { + progress.set_status("Finished"); + break; + } + } + + /* Don't go in pause mode when preview kernels are used + * When feature kernels become available the session will be resetted. */ + else if (no_tiles && kernel_state == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { + time_sleep(0.1); + } + else if (no_tiles && kernel_state == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE) { + reset_cpu(tile_manager.params, params.samples); + } + + else { + /* if in interactive mode, and we are either paused or done for now, + * wait for pause condition notify to wake up again */ + thread_scoped_lock pause_lock(pause_mutex); + + if (!pause && delayed_reset.do_reset) { + /* reset once to start */ + thread_scoped_lock reset_lock(delayed_reset.mutex); + thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock display_lock(display_mutex); + + reset_(delayed_reset.params, delayed_reset.samples); + delayed_reset.do_reset = false; + } + else if (pause || no_tiles) { + update_status_time(pause, no_tiles); + + while (1) { + scoped_timer pause_timer; + pause_cond.wait(pause_lock); + if (pause) { + progress.add_skip_time(pause_timer, params.background); + } + + update_status_time(pause, no_tiles); + progress.set_update(); + + if (!pause) + break; + } + } + + if (progress.get_cancel()) + break; + } + + if (!no_tiles) { + /* buffers mutex is locked entirely while rendering each + * sample, and released/reacquired on each iteration to allow + * reset and draw in between */ + thread_scoped_lock buffers_lock(buffers_mutex); + + /* update scene */ + scoped_timer update_timer; + if (update_scene()) { + profiler.reset(scene->shaders.size(), scene->objects.size()); + } + progress.add_skip_time(update_timer, params.background); + + if (!device->error_message().empty()) + progress.set_error(device->error_message()); + + if (progress.get_cancel()) + break; + + /* update status and timing */ + update_status_time(); + + /* render */ + render(); + + /* update status and timing */ + update_status_time(); + + if (!params.background) + need_tonemap = true; + + if (!device->error_message().empty()) + progress.set_error(device->error_message()); + } + + device->task_wait(); + + { + thread_scoped_lock reset_lock(delayed_reset.mutex); + thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock display_lock(display_mutex); + + if (delayed_reset.do_reset) { + /* reset rendering if request from main thread */ + delayed_reset.do_reset = false; + reset_(delayed_reset.params, delayed_reset.samples); + } + else if (need_tonemap) { + /* tonemap only if we do not reset, we don't we don't + * want to show the result of an incomplete sample */ + tonemap(tile_manager.state.sample); + } + + if (!device->error_message().empty()) + progress.set_error(device->error_message()); + + tiles_written = update_progressive_refine(progress.get_cancel()); + } + + progress.set_update(); + } + + if (!tiles_written) + update_progressive_refine(true); } DeviceRequestedFeatures Session::get_requested_device_features() { - /* TODO(sergey): Consider moving this to the Scene level. */ - DeviceRequestedFeatures requested_features; - requested_features.experimental = params.experimental; - - scene->shader_manager->get_requested_features( - scene, - &requested_features); - - /* This features are not being tweaked as often as shaders, - * so could be done selective magic for the viewport as well. - */ - bool use_motion = scene->need_motion() == Scene::MotionType::MOTION_BLUR; - requested_features.use_hair = false; - requested_features.use_object_motion = false; - requested_features.use_camera_motion = use_motion && scene->camera->use_motion(); - foreach(Object *object, scene->objects) { - Mesh *mesh = object->mesh; - if(mesh->num_curves()) { - requested_features.use_hair = true; - } - if (use_motion) { - requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur; - requested_features.use_camera_motion |= mesh->use_motion_blur; - } + /* TODO(sergey): Consider moving this to the Scene level. */ + DeviceRequestedFeatures requested_features; + requested_features.experimental = params.experimental; + + scene->shader_manager->get_requested_features(scene, &requested_features); + + /* This features are not being tweaked as often as shaders, + * so could be done selective magic for the viewport as well. + */ + bool use_motion = scene->need_motion() == Scene::MotionType::MOTION_BLUR; + requested_features.use_hair = false; + requested_features.use_object_motion = false; + requested_features.use_camera_motion = use_motion && scene->camera->use_motion(); + foreach (Object *object, scene->objects) { + Mesh *mesh = object->mesh; + if (mesh->num_curves()) { + requested_features.use_hair = true; + } + if (use_motion) { + requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur; + requested_features.use_camera_motion |= mesh->use_motion_blur; + } #ifdef WITH_OPENSUBDIV - if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { - requested_features.use_patch_evaluation = true; - } + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { + requested_features.use_patch_evaluation = true; + } #endif - if(object->is_shadow_catcher) { - requested_features.use_shadow_tricks = true; - } - requested_features.use_true_displacement |= mesh->has_true_displacement(); - } - - requested_features.use_background_light = scene->light_manager->has_background_light(scene); - - BakeManager *bake_manager = scene->bake_manager; - requested_features.use_baking = bake_manager->get_baking(); - requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH); - if(params.run_denoising) { - requested_features.use_denoising = true; - requested_features.use_shadow_tricks = true; - } - - return requested_features; + if (object->is_shadow_catcher) { + requested_features.use_shadow_tricks = true; + } + requested_features.use_true_displacement |= mesh->has_true_displacement(); + } + + requested_features.use_background_light = scene->light_manager->has_background_light(scene); + + BakeManager *bake_manager = scene->bake_manager; + requested_features.use_baking = bake_manager->get_baking(); + requested_features.use_integrator_branched = (scene->integrator->method == + Integrator::BRANCHED_PATH); + if (params.run_denoising) { + requested_features.use_denoising = true; + requested_features.use_shadow_tricks = true; + } + + return requested_features; } bool Session::load_kernels(bool lock_scene) { - thread_scoped_lock scene_lock; - if(lock_scene) { - scene_lock = thread_scoped_lock(scene->mutex); - } - - DeviceRequestedFeatures requested_features = get_requested_device_features(); - - if(!kernels_loaded || loaded_kernel_features.modified(requested_features)) { - progress.set_status("Loading render kernels (may take a few minutes the first time)"); - - scoped_timer timer; - - VLOG(2) << "Requested features:\n" << requested_features; - if(!device->load_kernels(requested_features)) { - string message = device->error_message(); - if(message.empty()) - message = "Failed loading render kernel, see console for errors"; - - progress.set_error(message); - progress.set_status("Error", message); - progress.set_update(); - return false; - } - - progress.add_skip_time(timer, false); - VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start(); - - kernels_loaded = true; - loaded_kernel_features = requested_features; - return true; - } - return false; + thread_scoped_lock scene_lock; + if (lock_scene) { + scene_lock = thread_scoped_lock(scene->mutex); + } + + DeviceRequestedFeatures requested_features = get_requested_device_features(); + + if (!kernels_loaded || loaded_kernel_features.modified(requested_features)) { + progress.set_status("Loading render kernels (may take a few minutes the first time)"); + + scoped_timer timer; + + VLOG(2) << "Requested features:\n" << requested_features; + if (!device->load_kernels(requested_features)) { + string message = device->error_message(); + if (message.empty()) + message = "Failed loading render kernel, see console for errors"; + + progress.set_error(message); + progress.set_status("Error", message); + progress.set_update(); + return false; + } + + progress.add_skip_time(timer, false); + VLOG(1) << "Total time spent loading kernels: " << time_dt() - timer.get_start(); + + kernels_loaded = true; + loaded_kernel_features = requested_features; + return true; + } + return false; } void Session::run() { - if(params.use_profiling && (params.device.type == DEVICE_CPU)) { - profiler.start(); - } - - /* session thread loop */ - progress.set_status("Waiting for render to start"); - - /* run */ - if(!progress.get_cancel()) { - /* reset number of rendered samples */ - progress.reset_sample(); - - if(device_use_gl) - run_gpu(); - else - run_cpu(); - } - - profiler.stop(); - - /* progress update */ - if(progress.get_cancel()) - progress.set_status("Cancel", progress.get_cancel_message()); - else - progress.set_update(); + if (params.use_profiling && (params.device.type == DEVICE_CPU)) { + profiler.start(); + } + + /* session thread loop */ + progress.set_status("Waiting for render to start"); + + /* run */ + if (!progress.get_cancel()) { + /* reset number of rendered samples */ + progress.reset_sample(); + + if (device_use_gl) + run_gpu(); + else + run_cpu(); + } + + profiler.stop(); + + /* progress update */ + if (progress.get_cancel()) + progress.set_status("Cancel", progress.get_cancel_message()); + else + progress.set_update(); } -bool Session::draw(BufferParams& buffer_params, DeviceDrawParams &draw_params) +bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params) { - if(device_use_gl) - return draw_gpu(buffer_params, draw_params); - else - return draw_cpu(buffer_params, draw_params); + if (device_use_gl) + return draw_gpu(buffer_params, draw_params); + else + return draw_cpu(buffer_params, draw_params); } -void Session::reset_(BufferParams& buffer_params, int samples) +void Session::reset_(BufferParams &buffer_params, int samples) { - if(buffers && buffer_params.modified(tile_manager.params)) { - gpu_draw_ready = false; - buffers->reset(buffer_params); - if(display) { - display->reset(buffer_params); - } - } - - tile_manager.reset(buffer_params, samples); - progress.reset_sample(); - - bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX; - progress.set_total_pixel_samples(show_progress? tile_manager.state.total_pixel_samples : 0); - - if(!params.background) - progress.set_start_time(); - progress.set_render_start_time(); + if (buffers && buffer_params.modified(tile_manager.params)) { + gpu_draw_ready = false; + buffers->reset(buffer_params); + if (display) { + display->reset(buffer_params); + } + } + + tile_manager.reset(buffer_params, samples); + progress.reset_sample(); + + bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX; + progress.set_total_pixel_samples(show_progress ? tile_manager.state.total_pixel_samples : 0); + + if (!params.background) + progress.set_start_time(); + progress.set_render_start_time(); } -void Session::reset(BufferParams& buffer_params, int samples) +void Session::reset(BufferParams &buffer_params, int samples) { - if(device_use_gl) - reset_gpu(buffer_params, samples); - else - reset_cpu(buffer_params, samples); + if (device_use_gl) + reset_gpu(buffer_params, samples); + else + reset_cpu(buffer_params, samples); } void Session::set_samples(int samples) { - if(samples != params.samples) { - params.samples = samples; - tile_manager.set_samples(samples); - - { - thread_scoped_lock pause_lock(pause_mutex); - } - pause_cond.notify_all(); - } + if (samples != params.samples) { + params.samples = samples; + tile_manager.set_samples(samples); + + { + thread_scoped_lock pause_lock(pause_mutex); + } + pause_cond.notify_all(); + } } void Session::set_pause(bool pause_) { - bool notify = false; + bool notify = false; - { - thread_scoped_lock pause_lock(pause_mutex); + { + thread_scoped_lock pause_lock(pause_mutex); - if(pause != pause_) { - pause = pause_; - notify = true; - } - } + if (pause != pause_) { + pause = pause_; + notify = true; + } + } - if(notify) - pause_cond.notify_all(); + if (notify) + pause_cond.notify_all(); } void Session::wait() { - if (session_thread) { - session_thread->join(); - delete session_thread; - } + if (session_thread) { + session_thread->join(); + delete session_thread; + } - session_thread = NULL; + session_thread = NULL; } bool Session::update_scene() { - thread_scoped_lock scene_lock(scene->mutex); - - /* update camera if dimensions changed for progressive render. the camera - * knows nothing about progressive or cropped rendering, it just gets the - * image dimensions passed in */ - Camera *cam = scene->camera; - int width = tile_manager.state.buffer.full_width; - int height = tile_manager.state.buffer.full_height; - int resolution = tile_manager.state.resolution_divider; - - if(width != cam->width || height != cam->height) { - cam->width = width; - cam->height = height; - cam->resolution = resolution; - cam->tag_update(); - } - - /* number of samples is needed by multi jittered - * sampling pattern and by baking */ - Integrator *integrator = scene->integrator; - BakeManager *bake_manager = scene->bake_manager; - - if(integrator->sampling_pattern == SAMPLING_PATTERN_CMJ || - bake_manager->get_baking()) - { - int aa_samples = tile_manager.num_samples; - - if(aa_samples != integrator->aa_samples) { - integrator->aa_samples = aa_samples; - integrator->tag_update(scene); - } - } - - /* update scene */ - if(scene->need_update()) { - bool new_kernels_needed = load_kernels(false); - - /* Update max_closures. */ - KernelIntegrator *kintegrator = &scene->dscene.data.integrator; - if(params.background) { - kintegrator->max_closures = get_max_closure_count(); - } - else { - /* Currently viewport render is faster with higher max_closures, needs investigating. */ - kintegrator->max_closures = MAX_CLOSURE; - } - - progress.set_status("Updating Scene"); - MEM_GUARDED_CALL(&progress, scene->device_update, device, progress); - - DeviceKernelStatus kernel_switch_status = device->get_active_kernel_switch_state(); - bool kernel_switch_needed = kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE || - kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_INVALID; - if (kernel_switch_status == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { - progress.set_kernel_status("Compiling render kernels"); - } - if (new_kernels_needed || kernel_switch_needed) { - progress.set_kernel_status("Compiling render kernels"); - device->wait_for_availability(loaded_kernel_features); - progress.set_kernel_status(""); - } - - if (kernel_switch_needed) { - reset(tile_manager.params, params.samples); - } - return true; - } - return false; + thread_scoped_lock scene_lock(scene->mutex); + + /* update camera if dimensions changed for progressive render. the camera + * knows nothing about progressive or cropped rendering, it just gets the + * image dimensions passed in */ + Camera *cam = scene->camera; + int width = tile_manager.state.buffer.full_width; + int height = tile_manager.state.buffer.full_height; + int resolution = tile_manager.state.resolution_divider; + + if (width != cam->width || height != cam->height) { + cam->width = width; + cam->height = height; + cam->resolution = resolution; + cam->tag_update(); + } + + /* number of samples is needed by multi jittered + * sampling pattern and by baking */ + Integrator *integrator = scene->integrator; + BakeManager *bake_manager = scene->bake_manager; + + if (integrator->sampling_pattern == SAMPLING_PATTERN_CMJ || bake_manager->get_baking()) { + int aa_samples = tile_manager.num_samples; + + if (aa_samples != integrator->aa_samples) { + integrator->aa_samples = aa_samples; + integrator->tag_update(scene); + } + } + + /* update scene */ + if (scene->need_update()) { + bool new_kernels_needed = load_kernels(false); + + /* Update max_closures. */ + KernelIntegrator *kintegrator = &scene->dscene.data.integrator; + if (params.background) { + kintegrator->max_closures = get_max_closure_count(); + } + else { + /* Currently viewport render is faster with higher max_closures, needs investigating. */ + kintegrator->max_closures = MAX_CLOSURE; + } + + progress.set_status("Updating Scene"); + MEM_GUARDED_CALL(&progress, scene->device_update, device, progress); + + DeviceKernelStatus kernel_switch_status = device->get_active_kernel_switch_state(); + bool kernel_switch_needed = kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE || + kernel_switch_status == DEVICE_KERNEL_FEATURE_KERNEL_INVALID; + if (kernel_switch_status == DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL) { + progress.set_kernel_status("Compiling render kernels"); + } + if (new_kernels_needed || kernel_switch_needed) { + progress.set_kernel_status("Compiling render kernels"); + device->wait_for_availability(loaded_kernel_features); + progress.set_kernel_status(""); + } + + if (kernel_switch_needed) { + reset(tile_manager.params, params.samples); + } + return true; + } + return false; } void Session::update_status_time(bool show_pause, bool show_done) { - int progressive_sample = tile_manager.state.sample; - int num_samples = tile_manager.get_num_effective_samples(); - - int tile = progress.get_rendered_tiles(); - int num_tiles = tile_manager.state.num_tiles; - - /* update status */ - string status, substatus; - - if(!params.progressive) { - const bool is_cpu = params.device.type == DEVICE_CPU; - const bool rendering_finished = (tile == num_tiles); - const bool is_last_tile = (tile + 1) == num_tiles; - - substatus = string_printf("Rendered %d/%d Tiles", tile, num_tiles); - - if(!rendering_finished && (device->show_samples() || (is_cpu && is_last_tile))) { - /* Some devices automatically support showing the sample number: - * - CUDADevice - * - OpenCLDevice when using the megakernel (the split kernel renders multiple - * samples at the same time, so the current sample isn't really defined) - * - CPUDevice when using one thread - * For these devices, the current sample is always shown. - * - * The other option is when the last tile is currently being rendered by the CPU. - */ - substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples); - } - if(params.full_denoising) { - substatus += string_printf(", Denoised %d tiles", progress.get_denoised_tiles()); - } - else if(params.run_denoising) { - substatus += string_printf(", Prefiltered %d tiles", progress.get_denoised_tiles()); - } - } - else if(tile_manager.num_samples == INT_MAX) - substatus = string_printf("Path Tracing Sample %d", progressive_sample+1); - else - substatus = string_printf("Path Tracing Sample %d/%d", - progressive_sample+1, - num_samples); - - if(show_pause) { - status = "Rendering Paused"; - } - else if(show_done) { - status = "Rendering Done"; - progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */ - } - else { - status = substatus; - substatus.clear(); - } - - progress.set_status(status, substatus); + int progressive_sample = tile_manager.state.sample; + int num_samples = tile_manager.get_num_effective_samples(); + + int tile = progress.get_rendered_tiles(); + int num_tiles = tile_manager.state.num_tiles; + + /* update status */ + string status, substatus; + + if (!params.progressive) { + const bool is_cpu = params.device.type == DEVICE_CPU; + const bool rendering_finished = (tile == num_tiles); + const bool is_last_tile = (tile + 1) == num_tiles; + + substatus = string_printf("Rendered %d/%d Tiles", tile, num_tiles); + + if (!rendering_finished && (device->show_samples() || (is_cpu && is_last_tile))) { + /* Some devices automatically support showing the sample number: + * - CUDADevice + * - OpenCLDevice when using the megakernel (the split kernel renders multiple + * samples at the same time, so the current sample isn't really defined) + * - CPUDevice when using one thread + * For these devices, the current sample is always shown. + * + * The other option is when the last tile is currently being rendered by the CPU. + */ + substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples); + } + if (params.full_denoising) { + substatus += string_printf(", Denoised %d tiles", progress.get_denoised_tiles()); + } + else if (params.run_denoising) { + substatus += string_printf(", Prefiltered %d tiles", progress.get_denoised_tiles()); + } + } + else if (tile_manager.num_samples == INT_MAX) + substatus = string_printf("Path Tracing Sample %d", progressive_sample + 1); + else + substatus = string_printf("Path Tracing Sample %d/%d", progressive_sample + 1, num_samples); + + if (show_pause) { + status = "Rendering Paused"; + } + else if (show_done) { + status = "Rendering Done"; + progress.set_end_time(); /* Save end time so that further calls to get_time are accurate. */ + } + else { + status = substatus; + substatus.clear(); + } + + progress.set_status(status, substatus); } void Session::render() { - /* Clear buffers. */ - if(buffers && tile_manager.state.sample == tile_manager.range_start_sample) { - buffers->zero(); - } - - /* Add path trace task. */ - DeviceTask task(DeviceTask::RENDER); - - task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2); - task.release_tile = function_bind(&Session::release_tile, this, _1); - task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2); - task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2); - task.get_cancel = function_bind(&Progress::get_cancel, &this->progress); - task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1); - task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2); - task.need_finish_queue = params.progressive_refine; - task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH; - task.requested_tile_size = params.tile_size; - task.passes_size = tile_manager.params.get_passes_size(); - - if(params.run_denoising) { - task.denoising = params.denoising; - - assert(!scene->film->need_update); - task.pass_stride = scene->film->pass_stride; - task.target_pass_stride = task.pass_stride; - task.pass_denoising_data = scene->film->denoising_data_offset; - task.pass_denoising_clean = scene->film->denoising_clean_offset; - - task.denoising_from_render = true; - task.denoising_do_filter = params.full_denoising; - task.denoising_write_passes = params.write_denoising_passes; - } - - device->task_add(task); + /* Clear buffers. */ + if (buffers && tile_manager.state.sample == tile_manager.range_start_sample) { + buffers->zero(); + } + + /* Add path trace task. */ + DeviceTask task(DeviceTask::RENDER); + + task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2); + task.release_tile = function_bind(&Session::release_tile, this, _1); + task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2); + task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2); + task.get_cancel = function_bind(&Progress::get_cancel, &this->progress); + task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1); + task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2); + task.need_finish_queue = params.progressive_refine; + task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH; + task.requested_tile_size = params.tile_size; + task.passes_size = tile_manager.params.get_passes_size(); + + if (params.run_denoising) { + task.denoising = params.denoising; + + assert(!scene->film->need_update); + task.pass_stride = scene->film->pass_stride; + task.target_pass_stride = task.pass_stride; + task.pass_denoising_data = scene->film->denoising_data_offset; + task.pass_denoising_clean = scene->film->denoising_clean_offset; + + task.denoising_from_render = true; + task.denoising_do_filter = params.full_denoising; + task.denoising_write_passes = params.write_denoising_passes; + } + + device->task_add(task); } void Session::tonemap(int sample) { - /* add tonemap task */ - DeviceTask task(DeviceTask::FILM_CONVERT); - - task.x = tile_manager.state.buffer.full_x; - task.y = tile_manager.state.buffer.full_y; - task.w = tile_manager.state.buffer.width; - task.h = tile_manager.state.buffer.height; - task.rgba_byte = display->rgba_byte.device_pointer; - task.rgba_half = display->rgba_half.device_pointer; - task.buffer = buffers->buffer.device_pointer; - task.sample = sample; - tile_manager.state.buffer.get_offset_stride(task.offset, task.stride); - - if(task.w > 0 && task.h > 0) { - device->task_add(task); - device->task_wait(); - - /* set display to new size */ - display->draw_set(task.w, task.h); - } - - display_outdated = false; + /* add tonemap task */ + DeviceTask task(DeviceTask::FILM_CONVERT); + + task.x = tile_manager.state.buffer.full_x; + task.y = tile_manager.state.buffer.full_y; + task.w = tile_manager.state.buffer.width; + task.h = tile_manager.state.buffer.height; + task.rgba_byte = display->rgba_byte.device_pointer; + task.rgba_half = display->rgba_half.device_pointer; + task.buffer = buffers->buffer.device_pointer; + task.sample = sample; + tile_manager.state.buffer.get_offset_stride(task.offset, task.stride); + + if (task.w > 0 && task.h > 0) { + device->task_add(task); + device->task_wait(); + + /* set display to new size */ + display->draw_set(task.w, task.h); + } + + display_outdated = false; } bool Session::update_progressive_refine(bool cancel) { - int sample = tile_manager.state.sample + 1; - bool write = sample == tile_manager.num_samples || cancel; - - double current_time = time_dt(); - - if(current_time - last_update_time < params.progressive_update_timeout) { - /* if last sample was processed, we need to write buffers anyway */ - if(!write && sample != 1) - return false; - } - - if(params.progressive_refine) { - foreach(Tile& tile, tile_manager.state.tiles) { - if(!tile.buffers) { - continue; - } - - RenderTile rtile; - rtile.x = tile_manager.state.buffer.full_x + tile.x; - rtile.y = tile_manager.state.buffer.full_y + tile.y; - rtile.w = tile.w; - rtile.h = tile.h; - rtile.sample = sample; - rtile.buffers = tile.buffers; - - if(write) { - if(write_render_tile_cb) - write_render_tile_cb(rtile); - } - else { - if(update_render_tile_cb) - update_render_tile_cb(rtile, true); - } - } - } - - last_update_time = current_time; - - return write; + int sample = tile_manager.state.sample + 1; + bool write = sample == tile_manager.num_samples || cancel; + + double current_time = time_dt(); + + if (current_time - last_update_time < params.progressive_update_timeout) { + /* if last sample was processed, we need to write buffers anyway */ + if (!write && sample != 1) + return false; + } + + if (params.progressive_refine) { + foreach (Tile &tile, tile_manager.state.tiles) { + if (!tile.buffers) { + continue; + } + + RenderTile rtile; + rtile.x = tile_manager.state.buffer.full_x + tile.x; + rtile.y = tile_manager.state.buffer.full_y + tile.y; + rtile.w = tile.w; + rtile.h = tile.h; + rtile.sample = sample; + rtile.buffers = tile.buffers; + + if (write) { + if (write_render_tile_cb) + write_render_tile_cb(rtile); + } + else { + if (update_render_tile_cb) + update_render_tile_cb(rtile, true); + } + } + } + + last_update_time = current_time; + + return write; } void Session::device_free() { - scene->device_free(); + scene->device_free(); - tile_manager.device_free(); + tile_manager.device_free(); - /* used from background render only, so no need to - * re-create render/display buffers here - */ + /* used from background render only, so no need to + * re-create render/display buffers here + */ } void Session::collect_statistics(RenderStats *render_stats) { - scene->collect_statistics(render_stats); - if(params.use_profiling && (params.device.type == DEVICE_CPU)) { - render_stats->collect_profiling(scene, profiler); - } + scene->collect_statistics(render_stats); + if (params.use_profiling && (params.device.type == DEVICE_CPU)) { + render_stats->collect_profiling(scene, profiler); + } } int Session::get_max_closure_count() { - if (scene->shader_manager->use_osl()) { - /* OSL always needs the maximum as we can't predict the - * number of closures a shader might generate. */ - return MAX_CLOSURE; - } - - int max_closures = 0; - for(int i = 0; i < scene->shaders.size(); i++) { - int num_closures = scene->shaders[i]->graph->get_num_closures(); - max_closures = max(max_closures, num_closures); - } - max_closure_global = max(max_closure_global, max_closures); - - if (max_closure_global > MAX_CLOSURE) { - /* This is usually harmless as more complex shader tend to get many - * closures discarded due to mixing or low weights. We need to limit - * to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it - * avoids excessive memory usage for split kernels. */ - VLOG(2) << "Maximum number of closures exceeded: " - << max_closure_global - << " > " - << MAX_CLOSURE; - - max_closure_global = MAX_CLOSURE; - } - - return max_closure_global; + if (scene->shader_manager->use_osl()) { + /* OSL always needs the maximum as we can't predict the + * number of closures a shader might generate. */ + return MAX_CLOSURE; + } + + int max_closures = 0; + for (int i = 0; i < scene->shaders.size(); i++) { + int num_closures = scene->shaders[i]->graph->get_num_closures(); + max_closures = max(max_closures, num_closures); + } + max_closure_global = max(max_closure_global, max_closures); + + if (max_closure_global > MAX_CLOSURE) { + /* This is usually harmless as more complex shader tend to get many + * closures discarded due to mixing or low weights. We need to limit + * to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it + * avoids excessive memory usage for split kernels. */ + VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > " + << MAX_CLOSURE; + + max_closure_global = MAX_CLOSURE; + } + + return max_closure_global; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 404b7b7a945..60d8f7a8b14 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -42,91 +42,83 @@ class Scene; /* Session Parameters */ class SessionParams { -public: - DeviceInfo device; - bool background; - bool progressive_refine; - - bool progressive; - bool experimental; - int samples; - int2 tile_size; - TileOrder tile_order; - int start_resolution; - int pixel_size; - int threads; - - bool use_profiling; - - bool display_buffer_linear; - - bool run_denoising; - bool write_denoising_passes; - bool full_denoising; - DenoiseParams denoising; - - double cancel_timeout; - double reset_timeout; - double text_timeout; - double progressive_update_timeout; - - ShadingSystem shadingsystem; - - function<bool(const uchar *pixels, - int width, - int height, - int channels)> write_render_cb; - - SessionParams() - { - background = false; - progressive_refine = false; - - progressive = false; - experimental = false; - samples = 1024; - tile_size = make_int2(64, 64); - start_resolution = INT_MAX; - pixel_size = 1; - threads = 0; - - use_profiling = false; - - run_denoising = false; - write_denoising_passes = false; - full_denoising = false; - - display_buffer_linear = false; - - cancel_timeout = 0.1; - reset_timeout = 0.1; - text_timeout = 1.0; - progressive_update_timeout = 1.0; - - shadingsystem = SHADINGSYSTEM_SVM; - tile_order = TILE_CENTER; - } - - bool modified(const SessionParams& params) - { return !(device == params.device - && background == params.background - && progressive_refine == params.progressive_refine - /* && samples == params.samples */ - && progressive == params.progressive - && experimental == params.experimental - && tile_size == params.tile_size - && start_resolution == params.start_resolution - && pixel_size == params.pixel_size - && threads == params.threads - && use_profiling == params.use_profiling - && display_buffer_linear == params.display_buffer_linear - && cancel_timeout == params.cancel_timeout - && reset_timeout == params.reset_timeout - && text_timeout == params.text_timeout - && progressive_update_timeout == params.progressive_update_timeout - && tile_order == params.tile_order - && shadingsystem == params.shadingsystem); } - + public: + DeviceInfo device; + bool background; + bool progressive_refine; + + bool progressive; + bool experimental; + int samples; + int2 tile_size; + TileOrder tile_order; + int start_resolution; + int pixel_size; + int threads; + + bool use_profiling; + + bool display_buffer_linear; + + bool run_denoising; + bool write_denoising_passes; + bool full_denoising; + DenoiseParams denoising; + + double cancel_timeout; + double reset_timeout; + double text_timeout; + double progressive_update_timeout; + + ShadingSystem shadingsystem; + + function<bool(const uchar *pixels, int width, int height, int channels)> write_render_cb; + + SessionParams() + { + background = false; + progressive_refine = false; + + progressive = false; + experimental = false; + samples = 1024; + tile_size = make_int2(64, 64); + start_resolution = INT_MAX; + pixel_size = 1; + threads = 0; + + use_profiling = false; + + run_denoising = false; + write_denoising_passes = false; + full_denoising = false; + + display_buffer_linear = false; + + cancel_timeout = 0.1; + reset_timeout = 0.1; + text_timeout = 1.0; + progressive_update_timeout = 1.0; + + shadingsystem = SHADINGSYSTEM_SVM; + tile_order = TILE_CENTER; + } + + bool modified(const SessionParams ¶ms) + { + return !(device == params.device && background == params.background && + progressive_refine == params.progressive_refine + /* && samples == params.samples */ + && progressive == params.progressive && experimental == params.experimental && + tile_size == params.tile_size && start_resolution == params.start_resolution && + pixel_size == params.pixel_size && threads == params.threads && + use_profiling == params.use_profiling && + display_buffer_linear == params.display_buffer_linear && + cancel_timeout == params.cancel_timeout && reset_timeout == params.reset_timeout && + text_timeout == params.text_timeout && + progressive_update_timeout == params.progressive_update_timeout && + tile_order == params.tile_order && shadingsystem == params.shadingsystem); + } }; /* Session @@ -135,111 +127,111 @@ public: * control loop and dispatching tasks. */ class Session { -public: - Device *device; - Scene *scene; - RenderBuffers *buffers; - DisplayBuffer *display; - Progress progress; - SessionParams params; - TileManager tile_manager; - Stats stats; - Profiler profiler; + public: + Device *device; + Scene *scene; + RenderBuffers *buffers; + DisplayBuffer *display; + Progress progress; + SessionParams params; + TileManager tile_manager; + Stats stats; + Profiler profiler; - function<void(RenderTile&)> write_render_tile_cb; - function<void(RenderTile&, bool)> update_render_tile_cb; + function<void(RenderTile &)> write_render_tile_cb; + function<void(RenderTile &, bool)> update_render_tile_cb; - explicit Session(const SessionParams& params); - ~Session(); + explicit Session(const SessionParams ¶ms); + ~Session(); - void start(); - bool draw(BufferParams& params, DeviceDrawParams& draw_params); - void wait(); + void start(); + bool draw(BufferParams ¶ms, DeviceDrawParams &draw_params); + void wait(); - bool ready_to_reset(); - void reset(BufferParams& params, int samples); - void set_samples(int samples); - void set_pause(bool pause); + bool ready_to_reset(); + void reset(BufferParams ¶ms, int samples); + void set_samples(int samples); + void set_pause(bool pause); - bool update_scene(); - bool load_kernels(bool lock_scene=true); + bool update_scene(); + bool load_kernels(bool lock_scene = true); - void device_free(); + void device_free(); - /* Returns the rendering progress or 0 if no progress can be determined - * (for example, when rendering with unlimited samples). */ - float get_progress(); + /* Returns the rendering progress or 0 if no progress can be determined + * (for example, when rendering with unlimited samples). */ + float get_progress(); - void collect_statistics(RenderStats *stats); + void collect_statistics(RenderStats *stats); -protected: - struct DelayedReset { - thread_mutex mutex; - bool do_reset; - BufferParams params; - int samples; - } delayed_reset; + protected: + struct DelayedReset { + thread_mutex mutex; + bool do_reset; + BufferParams params; + int samples; + } delayed_reset; - void run(); + void run(); - void update_status_time(bool show_pause = false, bool show_done = false); + void update_status_time(bool show_pause = false, bool show_done = false); - void tonemap(int sample); - void render(); - void reset_(BufferParams& params, int samples); + void tonemap(int sample); + void render(); + void reset_(BufferParams ¶ms, int samples); - void run_cpu(); - bool draw_cpu(BufferParams& params, DeviceDrawParams& draw_params); - void reset_cpu(BufferParams& params, int samples); + void run_cpu(); + bool draw_cpu(BufferParams ¶ms, DeviceDrawParams &draw_params); + void reset_cpu(BufferParams ¶ms, int samples); - void run_gpu(); - bool draw_gpu(BufferParams& params, DeviceDrawParams& draw_params); - void reset_gpu(BufferParams& params, int samples); + void run_gpu(); + bool draw_gpu(BufferParams ¶ms, DeviceDrawParams &draw_params); + void reset_gpu(BufferParams ¶ms, int samples); - bool acquire_tile(Device *tile_device, RenderTile& tile); - void update_tile_sample(RenderTile& tile); - void release_tile(RenderTile& tile); + bool acquire_tile(Device *tile_device, RenderTile &tile); + void update_tile_sample(RenderTile &tile); + void release_tile(RenderTile &tile); - void map_neighbor_tiles(RenderTile *tiles, Device *tile_device); - void unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device); + void map_neighbor_tiles(RenderTile *tiles, Device *tile_device); + void unmap_neighbor_tiles(RenderTile *tiles, Device *tile_device); - bool device_use_gl; + bool device_use_gl; - thread *session_thread; + thread *session_thread; - volatile bool display_outdated; + volatile bool display_outdated; - volatile bool gpu_draw_ready; - volatile bool gpu_need_tonemap; - thread_condition_variable gpu_need_tonemap_cond; + volatile bool gpu_draw_ready; + volatile bool gpu_need_tonemap; + thread_condition_variable gpu_need_tonemap_cond; - bool pause; - thread_condition_variable pause_cond; - thread_mutex pause_mutex; - thread_mutex tile_mutex; - thread_mutex buffers_mutex; - thread_mutex display_mutex; + bool pause; + thread_condition_variable pause_cond; + thread_mutex pause_mutex; + thread_mutex tile_mutex; + thread_mutex buffers_mutex; + thread_mutex display_mutex; - bool kernels_loaded; - DeviceRequestedFeatures loaded_kernel_features; + bool kernels_loaded; + DeviceRequestedFeatures loaded_kernel_features; - double reset_time; + double reset_time; - /* progressive refine */ - double last_update_time; - bool update_progressive_refine(bool cancel); + /* progressive refine */ + double last_update_time; + bool update_progressive_refine(bool cancel); - DeviceRequestedFeatures get_requested_device_features(); + DeviceRequestedFeatures get_requested_device_features(); - /* ** Split kernel routines ** */ + /* ** Split kernel routines ** */ - /* Maximumnumber of closure during session lifetime. */ - int max_closure_global; + /* Maximumnumber of closure during session lifetime. */ + int max_closure_global; - /* Get maximum number of closures to be used in kernel. */ - int get_max_closure_count(); + /* Get maximum number of closures to be used in kernel. */ + int get_max_closure_count(); }; CCL_NAMESPACE_END -#endif /* __SESSION_H__ */ +#endif /* __SESSION_H__ */ diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 3c94f2dfb59..ac3303cbfeb 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -48,16 +48,15 @@ bool ShaderManager::beckmann_table_ready = false; /* 2D slope distribution (alpha = 1.0) */ static float beckmann_table_P22(const float slope_x, const float slope_y) { - return expf(-(slope_x*slope_x + slope_y*slope_y)); + return expf(-(slope_x * slope_x + slope_y * slope_y)); } /* maximal slope amplitude (range that contains 99.99% of the distribution) */ static float beckmann_table_slope_max() { - return 6.0; + return 6.0; } - /* MSVC 2015 needs this ugly hack to prevent a codegen bug on x86 * see T50176 for details */ @@ -74,327 +73,331 @@ static float beckmann_table_slope_max() */ static void beckmann_table_rows(float *table, int row_from, int row_to) { - /* allocate temporary data */ - const int DATA_TMP_SIZE = 512; - vector<double> slope_x(DATA_TMP_SIZE); - vector<double> CDF_P22_omega_i(DATA_TMP_SIZE); - - /* loop over incident directions */ - for(int index_theta = row_from; index_theta < row_to; index_theta++) { - /* incident vector */ - const float cos_theta = index_theta / (BECKMANN_TABLE_SIZE - 1.0f); - const float sin_theta = safe_sqrtf(1.0f - cos_theta*cos_theta); - - /* for a given incident vector - * integrate P22_{omega_i}(x_slope, 1, 1), Eq. (10) */ - slope_x[0] = (double)-beckmann_table_slope_max(); - CDF_P22_omega_i[0] = 0; - - for(MSVC_VOLATILE int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) { - /* slope_x */ - slope_x[index_slope_x] = (double)(-beckmann_table_slope_max() + 2.0f * beckmann_table_slope_max() * index_slope_x/(DATA_TMP_SIZE - 1.0f)); - - /* dot product with incident vector */ - float dot_product = fmaxf(0.0f, -(float)slope_x[index_slope_x]*sin_theta + cos_theta); - /* marginalize P22_{omega_i}(x_slope, 1, 1), Eq. (10) */ - float P22_omega_i = 0.0f; - - for(int j = 0; j < 100; ++j) { - float slope_y = -beckmann_table_slope_max() + 2.0f * beckmann_table_slope_max() * j * (1.0f/99.0f); - P22_omega_i += dot_product * beckmann_table_P22((float)slope_x[index_slope_x], slope_y); - } - - /* CDF of P22_{omega_i}(x_slope, 1, 1), Eq. (10) */ - CDF_P22_omega_i[index_slope_x] = CDF_P22_omega_i[index_slope_x - 1] + (double)P22_omega_i; - } - - /* renormalize CDF_P22_omega_i */ - for(int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) - CDF_P22_omega_i[index_slope_x] /= CDF_P22_omega_i[DATA_TMP_SIZE - 1]; - - /* loop over random number U1 */ - int index_slope_x = 0; - - for(int index_U = 0; index_U < BECKMANN_TABLE_SIZE; ++index_U) { - const double U = 0.0000001 + 0.9999998 * index_U / (double)(BECKMANN_TABLE_SIZE - 1); - - /* inverse CDF_P22_omega_i, solve Eq.(11) */ - while(CDF_P22_omega_i[index_slope_x] <= U) - ++index_slope_x; - - const double interp = - (CDF_P22_omega_i[index_slope_x] - U) / - (CDF_P22_omega_i[index_slope_x] - CDF_P22_omega_i[index_slope_x - 1]); - - /* store value */ - table[index_U + index_theta*BECKMANN_TABLE_SIZE] = (float)( - interp * slope_x[index_slope_x - 1] + - (1.0 - interp) * slope_x[index_slope_x]); - } - } + /* allocate temporary data */ + const int DATA_TMP_SIZE = 512; + vector<double> slope_x(DATA_TMP_SIZE); + vector<double> CDF_P22_omega_i(DATA_TMP_SIZE); + + /* loop over incident directions */ + for (int index_theta = row_from; index_theta < row_to; index_theta++) { + /* incident vector */ + const float cos_theta = index_theta / (BECKMANN_TABLE_SIZE - 1.0f); + const float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta); + + /* for a given incident vector + * integrate P22_{omega_i}(x_slope, 1, 1), Eq. (10) */ + slope_x[0] = (double)-beckmann_table_slope_max(); + CDF_P22_omega_i[0] = 0; + + for (MSVC_VOLATILE int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) { + /* slope_x */ + slope_x[index_slope_x] = (double)(-beckmann_table_slope_max() + + 2.0f * beckmann_table_slope_max() * index_slope_x / + (DATA_TMP_SIZE - 1.0f)); + + /* dot product with incident vector */ + float dot_product = fmaxf(0.0f, -(float)slope_x[index_slope_x] * sin_theta + cos_theta); + /* marginalize P22_{omega_i}(x_slope, 1, 1), Eq. (10) */ + float P22_omega_i = 0.0f; + + for (int j = 0; j < 100; ++j) { + float slope_y = -beckmann_table_slope_max() + + 2.0f * beckmann_table_slope_max() * j * (1.0f / 99.0f); + P22_omega_i += dot_product * beckmann_table_P22((float)slope_x[index_slope_x], slope_y); + } + + /* CDF of P22_{omega_i}(x_slope, 1, 1), Eq. (10) */ + CDF_P22_omega_i[index_slope_x] = CDF_P22_omega_i[index_slope_x - 1] + (double)P22_omega_i; + } + + /* renormalize CDF_P22_omega_i */ + for (int index_slope_x = 1; index_slope_x < DATA_TMP_SIZE; ++index_slope_x) + CDF_P22_omega_i[index_slope_x] /= CDF_P22_omega_i[DATA_TMP_SIZE - 1]; + + /* loop over random number U1 */ + int index_slope_x = 0; + + for (int index_U = 0; index_U < BECKMANN_TABLE_SIZE; ++index_U) { + const double U = 0.0000001 + 0.9999998 * index_U / (double)(BECKMANN_TABLE_SIZE - 1); + + /* inverse CDF_P22_omega_i, solve Eq.(11) */ + while (CDF_P22_omega_i[index_slope_x] <= U) + ++index_slope_x; + + const double interp = (CDF_P22_omega_i[index_slope_x] - U) / + (CDF_P22_omega_i[index_slope_x] - CDF_P22_omega_i[index_slope_x - 1]); + + /* store value */ + table[index_U + index_theta * BECKMANN_TABLE_SIZE] = + (float)(interp * slope_x[index_slope_x - 1] + (1.0 - interp) * slope_x[index_slope_x]); + } + } } #undef MSVC_VOLATILE -static void beckmann_table_build(vector<float>& table) +static void beckmann_table_build(vector<float> &table) { - table.resize(BECKMANN_TABLE_SIZE*BECKMANN_TABLE_SIZE); + table.resize(BECKMANN_TABLE_SIZE * BECKMANN_TABLE_SIZE); - /* multithreaded build */ - TaskPool pool; + /* multithreaded build */ + TaskPool pool; - for(int i = 0; i < BECKMANN_TABLE_SIZE; i+=8) - pool.push(function_bind(&beckmann_table_rows, &table[0], i, i+8)); + for (int i = 0; i < BECKMANN_TABLE_SIZE; i += 8) + pool.push(function_bind(&beckmann_table_rows, &table[0], i, i + 8)); - pool.wait_work(); + pool.wait_work(); } /* Shader */ NODE_DEFINE(Shader) { - NodeType* type = NodeType::add("shader", create); - - SOCKET_BOOLEAN(use_mis, "Use MIS", true); - SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true); - SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true); - - static NodeEnum volume_sampling_method_enum; - volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE); - volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR); - volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE); - SOCKET_ENUM(volume_sampling_method, "Volume Sampling Method", volume_sampling_method_enum, VOLUME_SAMPLING_DISTANCE); - - static NodeEnum volume_interpolation_method_enum; - volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR); - volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC); - SOCKET_ENUM(volume_interpolation_method, "Volume Interpolation Method", volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR); - - static NodeEnum displacement_method_enum; - displacement_method_enum.insert("bump", DISPLACE_BUMP); - displacement_method_enum.insert("true", DISPLACE_TRUE); - displacement_method_enum.insert("both", DISPLACE_BOTH); - SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP); - - return type; + NodeType *type = NodeType::add("shader", create); + + SOCKET_BOOLEAN(use_mis, "Use MIS", true); + SOCKET_BOOLEAN(use_transparent_shadow, "Use Transparent Shadow", true); + SOCKET_BOOLEAN(heterogeneous_volume, "Heterogeneous Volume", true); + + static NodeEnum volume_sampling_method_enum; + volume_sampling_method_enum.insert("distance", VOLUME_SAMPLING_DISTANCE); + volume_sampling_method_enum.insert("equiangular", VOLUME_SAMPLING_EQUIANGULAR); + volume_sampling_method_enum.insert("multiple_importance", VOLUME_SAMPLING_MULTIPLE_IMPORTANCE); + SOCKET_ENUM(volume_sampling_method, + "Volume Sampling Method", + volume_sampling_method_enum, + VOLUME_SAMPLING_DISTANCE); + + static NodeEnum volume_interpolation_method_enum; + volume_interpolation_method_enum.insert("linear", VOLUME_INTERPOLATION_LINEAR); + volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC); + SOCKET_ENUM(volume_interpolation_method, + "Volume Interpolation Method", + volume_interpolation_method_enum, + VOLUME_INTERPOLATION_LINEAR); + + static NodeEnum displacement_method_enum; + displacement_method_enum.insert("bump", DISPLACE_BUMP); + displacement_method_enum.insert("true", DISPLACE_TRUE); + displacement_method_enum.insert("both", DISPLACE_BOTH); + SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP); + + return type; } -Shader::Shader() -: Node(node_type) +Shader::Shader() : Node(node_type) { - pass_id = 0; - - graph = NULL; - - has_surface = false; - has_surface_transparent = false; - has_surface_emission = false; - has_surface_bssrdf = false; - has_volume = false; - has_displacement = false; - has_bump = false; - has_bssrdf_bump = false; - has_surface_spatial_varying = false; - has_volume_spatial_varying = false; - has_object_dependency = false; - has_attribute_dependency = false; - has_integrator_dependency = false; - has_volume_connected = false; - - displacement_method = DISPLACE_BUMP; - - id = -1; - used = false; - - need_update = true; - need_update_mesh = true; - need_sync_object = false; + pass_id = 0; + + graph = NULL; + + has_surface = false; + has_surface_transparent = false; + has_surface_emission = false; + has_surface_bssrdf = false; + has_volume = false; + has_displacement = false; + has_bump = false; + has_bssrdf_bump = false; + has_surface_spatial_varying = false; + has_volume_spatial_varying = false; + has_object_dependency = false; + has_attribute_dependency = false; + has_integrator_dependency = false; + has_volume_connected = false; + + displacement_method = DISPLACE_BUMP; + + id = -1; + used = false; + + need_update = true; + need_update_mesh = true; + need_sync_object = false; } Shader::~Shader() { - delete graph; + delete graph; } bool Shader::is_constant_emission(float3 *emission) { - ShaderInput *surf = graph->output()->input("Surface"); + ShaderInput *surf = graph->output()->input("Surface"); - if(surf->link == NULL) { - return false; - } + if (surf->link == NULL) { + return false; + } - if(surf->link->parent->type == EmissionNode::node_type) { - EmissionNode *node = (EmissionNode*) surf->link->parent; + if (surf->link->parent->type == EmissionNode::node_type) { + EmissionNode *node = (EmissionNode *)surf->link->parent; - assert(node->input("Color")); - assert(node->input("Strength")); + assert(node->input("Color")); + assert(node->input("Strength")); - if(node->input("Color")->link || node->input("Strength")->link) { - return false; - } + if (node->input("Color")->link || node->input("Strength")->link) { + return false; + } - *emission = node->color*node->strength; - } - else if(surf->link->parent->type == BackgroundNode::node_type) { - BackgroundNode *node = (BackgroundNode*) surf->link->parent; + *emission = node->color * node->strength; + } + else if (surf->link->parent->type == BackgroundNode::node_type) { + BackgroundNode *node = (BackgroundNode *)surf->link->parent; - assert(node->input("Color")); - assert(node->input("Strength")); + assert(node->input("Color")); + assert(node->input("Strength")); - if(node->input("Color")->link || node->input("Strength")->link) { - return false; - } + if (node->input("Color")->link || node->input("Strength")->link) { + return false; + } - *emission = node->color*node->strength; - } - else { - return false; - } + *emission = node->color * node->strength; + } + else { + return false; + } - return true; + return true; } void Shader::set_graph(ShaderGraph *graph_) { - /* do this here already so that we can detect if mesh or object attributes - * are needed, since the node attribute callbacks check if their sockets - * are connected but proxy nodes should not count */ - if(graph_) { - graph_->remove_proxy_nodes(); - - if(displacement_method != DISPLACE_BUMP) { - graph_->compute_displacement_hash(); - } - } - - /* update geometry if displacement changed */ - if(displacement_method != DISPLACE_BUMP) { - const char *old_hash = (graph)? graph->displacement_hash.c_str() : ""; - const char *new_hash = (graph_)? graph_->displacement_hash.c_str() : ""; - - if(strcmp(old_hash, new_hash) != 0) { - need_update_mesh = true; - } - } - - /* assign graph */ - delete graph; - graph = graph_; - - /* Store info here before graph optimization to make sure that - * nodes that get optimized away still count. */ - has_volume_connected = (graph->output()->input("Volume")->link != NULL); + /* do this here already so that we can detect if mesh or object attributes + * are needed, since the node attribute callbacks check if their sockets + * are connected but proxy nodes should not count */ + if (graph_) { + graph_->remove_proxy_nodes(); + + if (displacement_method != DISPLACE_BUMP) { + graph_->compute_displacement_hash(); + } + } + + /* update geometry if displacement changed */ + if (displacement_method != DISPLACE_BUMP) { + const char *old_hash = (graph) ? graph->displacement_hash.c_str() : ""; + const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : ""; + + if (strcmp(old_hash, new_hash) != 0) { + need_update_mesh = true; + } + } + + /* assign graph */ + delete graph; + graph = graph_; + + /* Store info here before graph optimization to make sure that + * nodes that get optimized away still count. */ + has_volume_connected = (graph->output()->input("Volume")->link != NULL); } void Shader::tag_update(Scene *scene) { - /* update tag */ - need_update = true; - scene->shader_manager->need_update = true; - - /* if the shader previously was emissive, update light distribution, - * if the new shader is emissive, a light manager update tag will be - * done in the shader manager device update. */ - if(use_mis && has_surface_emission) - scene->light_manager->need_update = true; - - /* Special handle of background MIS light for now: for some reason it - * has use_mis set to false. We are quite close to release now, so - * better to be safe. - */ - if(this == scene->default_background && - scene->light_manager->has_background_light(scene)) - { - scene->light_manager->need_update = true; - } - - /* quick detection of which kind of shaders we have to avoid loading - * e.g. surface attributes when there is only a volume shader. this could - * be more fine grained but it's better than nothing */ - OutputNode *output = graph->output(); - bool prev_has_volume = has_volume; - has_surface = has_surface || output->input("Surface")->link; - has_volume = has_volume || output->input("Volume")->link; - has_displacement = has_displacement || output->input("Displacement")->link; - - /* get requested attributes. this could be optimized by pruning unused - * nodes here already, but that's the job of the shader manager currently, - * and may not be so great for interactive rendering where you temporarily - * disconnect a node */ - - AttributeRequestSet prev_attributes = attributes; - - attributes.clear(); - foreach(ShaderNode *node, graph->nodes) - node->attributes(this, &attributes); - - if(has_displacement && displacement_method == DISPLACE_BOTH) { - attributes.add(ATTR_STD_POSITION_UNDISPLACED); - } - - /* compare if the attributes changed, mesh manager will check - * need_update_mesh, update the relevant meshes and clear it. */ - if(attributes.modified(prev_attributes)) { - need_update_mesh = true; - scene->mesh_manager->need_update = true; - } - - if(has_volume != prev_has_volume) { - scene->mesh_manager->need_flags_update = true; - scene->object_manager->need_flags_update = true; - } + /* update tag */ + need_update = true; + scene->shader_manager->need_update = true; + + /* if the shader previously was emissive, update light distribution, + * if the new shader is emissive, a light manager update tag will be + * done in the shader manager device update. */ + if (use_mis && has_surface_emission) + scene->light_manager->need_update = true; + + /* Special handle of background MIS light for now: for some reason it + * has use_mis set to false. We are quite close to release now, so + * better to be safe. + */ + if (this == scene->default_background && scene->light_manager->has_background_light(scene)) { + scene->light_manager->need_update = true; + } + + /* quick detection of which kind of shaders we have to avoid loading + * e.g. surface attributes when there is only a volume shader. this could + * be more fine grained but it's better than nothing */ + OutputNode *output = graph->output(); + bool prev_has_volume = has_volume; + has_surface = has_surface || output->input("Surface")->link; + has_volume = has_volume || output->input("Volume")->link; + has_displacement = has_displacement || output->input("Displacement")->link; + + /* get requested attributes. this could be optimized by pruning unused + * nodes here already, but that's the job of the shader manager currently, + * and may not be so great for interactive rendering where you temporarily + * disconnect a node */ + + AttributeRequestSet prev_attributes = attributes; + + attributes.clear(); + foreach (ShaderNode *node, graph->nodes) + node->attributes(this, &attributes); + + if (has_displacement && displacement_method == DISPLACE_BOTH) { + attributes.add(ATTR_STD_POSITION_UNDISPLACED); + } + + /* compare if the attributes changed, mesh manager will check + * need_update_mesh, update the relevant meshes and clear it. */ + if (attributes.modified(prev_attributes)) { + need_update_mesh = true; + scene->mesh_manager->need_update = true; + } + + if (has_volume != prev_has_volume) { + scene->mesh_manager->need_flags_update = true; + scene->object_manager->need_flags_update = true; + } } void Shader::tag_used(Scene *scene) { - /* if an unused shader suddenly gets used somewhere, it needs to be - * recompiled because it was skipped for compilation before */ - if(!used) { - need_update = true; - scene->shader_manager->need_update = true; - } + /* if an unused shader suddenly gets used somewhere, it needs to be + * recompiled because it was skipped for compilation before */ + if (!used) { + need_update = true; + scene->shader_manager->need_update = true; + } } /* Shader Manager */ ShaderManager::ShaderManager() { - need_update = true; - beckmann_table_offset = TABLE_OFFSET_INVALID; + need_update = true; + beckmann_table_offset = TABLE_OFFSET_INVALID; - xyz_to_r = make_float3( 3.2404542f, -1.5371385f, -0.4985314f); - xyz_to_g = make_float3(-0.9692660f, 1.8760108f, 0.0415560f); - xyz_to_b = make_float3( 0.0556434f, -0.2040259f, 1.0572252f); - rgb_to_y = make_float3( 0.2126729f, 0.7151522f, 0.0721750f); + xyz_to_r = make_float3(3.2404542f, -1.5371385f, -0.4985314f); + xyz_to_g = make_float3(-0.9692660f, 1.8760108f, 0.0415560f); + xyz_to_b = make_float3(0.0556434f, -0.2040259f, 1.0572252f); + rgb_to_y = make_float3(0.2126729f, 0.7151522f, 0.0721750f); #ifdef WITH_OCIO - OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); - if(config) { - if(config->hasRole("XYZ") && config->hasRole("scene_linear")) { - OCIO::ConstProcessorRcPtr to_rgb_processor = config->getProcessor("XYZ", "scene_linear"); - OCIO::ConstProcessorRcPtr to_xyz_processor = config->getProcessor("scene_linear", "XYZ"); - if(to_rgb_processor && to_xyz_processor) { - float r[] = {1.0f, 0.0f, 0.0f}; - float g[] = {0.0f, 1.0f, 0.0f}; - float b[] = {0.0f, 0.0f, 1.0f}; - to_xyz_processor->applyRGB(r); - to_xyz_processor->applyRGB(g); - to_xyz_processor->applyRGB(b); - rgb_to_y = make_float3(r[1], g[1], b[1]); - - float x[] = {1.0f, 0.0f, 0.0f}; - float y[] = {0.0f, 1.0f, 0.0f}; - float z[] = {0.0f, 0.0f, 1.0f}; - to_rgb_processor->applyRGB(x); - to_rgb_processor->applyRGB(y); - to_rgb_processor->applyRGB(z); - xyz_to_r = make_float3(x[0], y[0], z[0]); - xyz_to_g = make_float3(x[1], y[1], z[1]); - xyz_to_b = make_float3(x[2], y[2], z[2]); - } - } - } + OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); + if (config) { + if (config->hasRole("XYZ") && config->hasRole("scene_linear")) { + OCIO::ConstProcessorRcPtr to_rgb_processor = config->getProcessor("XYZ", "scene_linear"); + OCIO::ConstProcessorRcPtr to_xyz_processor = config->getProcessor("scene_linear", "XYZ"); + if (to_rgb_processor && to_xyz_processor) { + float r[] = {1.0f, 0.0f, 0.0f}; + float g[] = {0.0f, 1.0f, 0.0f}; + float b[] = {0.0f, 0.0f, 1.0f}; + to_xyz_processor->applyRGB(r); + to_xyz_processor->applyRGB(g); + to_xyz_processor->applyRGB(b); + rgb_to_y = make_float3(r[1], g[1], b[1]); + + float x[] = {1.0f, 0.0f, 0.0f}; + float y[] = {0.0f, 1.0f, 0.0f}; + float z[] = {0.0f, 0.0f, 1.0f}; + to_rgb_processor->applyRGB(x); + to_rgb_processor->applyRGB(y); + to_rgb_processor->applyRGB(z); + xyz_to_r = make_float3(x[0], y[0], z[0]); + xyz_to_g = make_float3(x[1], y[1], z[1]); + xyz_to_b = make_float3(x[2], y[2], z[2]); + } + } + } #endif } @@ -404,337 +407,337 @@ ShaderManager::~ShaderManager() ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem) { - ShaderManager *manager; + ShaderManager *manager; - (void) shadingsystem; /* Ignored when built without OSL. */ + (void)shadingsystem; /* Ignored when built without OSL. */ #ifdef WITH_OSL - if(shadingsystem == SHADINGSYSTEM_OSL) { - manager = new OSLShaderManager(); - } - else + if (shadingsystem == SHADINGSYSTEM_OSL) { + manager = new OSLShaderManager(); + } + else #endif - { - manager = new SVMShaderManager(); - } + { + manager = new SVMShaderManager(); + } - add_default(scene); + add_default(scene); - return manager; + return manager; } uint ShaderManager::get_attribute_id(ustring name) { - thread_scoped_spin_lock lock(attribute_lock_); + thread_scoped_spin_lock lock(attribute_lock_); - /* get a unique id for each name, for SVM attribute lookup */ - AttributeIDMap::iterator it = unique_attribute_id.find(name); + /* get a unique id for each name, for SVM attribute lookup */ + AttributeIDMap::iterator it = unique_attribute_id.find(name); - if(it != unique_attribute_id.end()) - return it->second; + if (it != unique_attribute_id.end()) + return it->second; - uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size(); - unique_attribute_id[name] = id; - return id; + uint id = (uint)ATTR_STD_NUM + unique_attribute_id.size(); + unique_attribute_id[name] = id; + return id; } uint ShaderManager::get_attribute_id(AttributeStandard std) { - return (uint)std; + return (uint)std; } int ShaderManager::get_shader_id(Shader *shader, bool smooth) { - /* get a shader id to pass to the kernel */ - int id = shader->id; + /* get a shader id to pass to the kernel */ + int id = shader->id; - /* smooth flag */ - if(smooth) - id |= SHADER_SMOOTH_NORMAL; + /* smooth flag */ + if (smooth) + id |= SHADER_SMOOTH_NORMAL; - /* default flags */ - id |= SHADER_CAST_SHADOW|SHADER_AREA_LIGHT; + /* default flags */ + id |= SHADER_CAST_SHADOW | SHADER_AREA_LIGHT; - return id; + return id; } void ShaderManager::device_update_shaders_used(Scene *scene) { - /* figure out which shaders are in use, so SVM/OSL can skip compiling them - * for speed and avoid loading image textures into memory */ - uint id = 0; - foreach(Shader *shader, scene->shaders) { - shader->used = false; - shader->id = id++; - } - - scene->default_surface->used = true; - scene->default_light->used = true; - scene->default_background->used = true; - scene->default_empty->used = true; - - if(scene->background->shader) - scene->background->shader->used = true; - - foreach(Mesh *mesh, scene->meshes) - foreach(Shader *shader, mesh->used_shaders) - shader->used = true; - - foreach(Light *light, scene->lights) - if(light->shader) - light->shader->used = true; + /* figure out which shaders are in use, so SVM/OSL can skip compiling them + * for speed and avoid loading image textures into memory */ + uint id = 0; + foreach (Shader *shader, scene->shaders) { + shader->used = false; + shader->id = id++; + } + + scene->default_surface->used = true; + scene->default_light->used = true; + scene->default_background->used = true; + scene->default_empty->used = true; + + if (scene->background->shader) + scene->background->shader->used = true; + + foreach (Mesh *mesh, scene->meshes) + foreach (Shader *shader, mesh->used_shaders) + shader->used = true; + + foreach (Light *light, scene->lights) + if (light->shader) + light->shader->used = true; } void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Scene *scene, - Progress& /*progress*/) + Progress & /*progress*/) { - dscene->shaders.free(); - - if(scene->shaders.size() == 0) - return; - - KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size()); - bool has_volumes = false; - bool has_transparent_shadow = false; - - foreach(Shader *shader, scene->shaders) { - uint flag = 0; - - if(shader->use_mis) - flag |= SD_USE_MIS; - if(shader->has_surface_transparent && shader->use_transparent_shadow) - flag |= SD_HAS_TRANSPARENT_SHADOW; - if(shader->has_volume) { - flag |= SD_HAS_VOLUME; - has_volumes = true; - - /* todo: this could check more fine grained, to skip useless volumes - * enclosed inside an opaque bsdf. - */ - flag |= SD_HAS_TRANSPARENT_SHADOW; - } - /* in this case we can assume transparent surface */ - if(shader->has_volume_connected && !shader->has_surface) - flag |= SD_HAS_ONLY_VOLUME; - if(shader->heterogeneous_volume && shader->has_volume_spatial_varying) - flag |= SD_HETEROGENEOUS_VOLUME; - if(shader->has_attribute_dependency) - flag |= SD_NEED_ATTRIBUTES; - if(shader->has_bssrdf_bump) - flag |= SD_HAS_BSSRDF_BUMP; - if(device->info.has_volume_decoupled) { - if(shader->volume_sampling_method == VOLUME_SAMPLING_EQUIANGULAR) - flag |= SD_VOLUME_EQUIANGULAR; - if(shader->volume_sampling_method == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE) - flag |= SD_VOLUME_MIS; - } - if(shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) - flag |= SD_VOLUME_CUBIC; - if(shader->has_bump) - flag |= SD_HAS_BUMP; - if(shader->displacement_method != DISPLACE_BUMP) - flag |= SD_HAS_DISPLACEMENT; - - /* constant emission check */ - float3 constant_emission = make_float3(0.0f, 0.0f, 0.0f); - if(shader->is_constant_emission(&constant_emission)) - flag |= SD_HAS_CONSTANT_EMISSION; - - uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); - - /* regular shader */ - kshader->flags = flag; - kshader->pass_id = shader->pass_id; - kshader->constant_emission[0] = constant_emission.x; - kshader->constant_emission[1] = constant_emission.y; - kshader->constant_emission[2] = constant_emission.z; - kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id); - kshader++; - - has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0; - } - - dscene->shaders.copy_to_device(); - - /* lookup tables */ - KernelTables *ktables = &dscene->data.tables; - - /* beckmann lookup table */ - if(beckmann_table_offset == TABLE_OFFSET_INVALID) { - if(!beckmann_table_ready) { - thread_scoped_lock lock(lookup_table_mutex); - if(!beckmann_table_ready) { - beckmann_table_build(beckmann_table); - beckmann_table_ready = true; - } - } - beckmann_table_offset = scene->lookup_tables->add_table(dscene, beckmann_table); - } - ktables->beckmann_offset = (int)beckmann_table_offset; - - /* integrator */ - KernelIntegrator *kintegrator = &dscene->data.integrator; - kintegrator->use_volumes = has_volumes; - /* TODO(sergey): De-duplicate with flags set in integrator.cpp. */ - kintegrator->transparent_shadows = has_transparent_shadow; - - /* film */ - KernelFilm *kfilm = &dscene->data.film; - /* color space, needs to be here because e.g. displacement shaders could depend on it */ - kfilm->xyz_to_r = float3_to_float4(xyz_to_r); - kfilm->xyz_to_g = float3_to_float4(xyz_to_g); - kfilm->xyz_to_b = float3_to_float4(xyz_to_b); - kfilm->rgb_to_y = float3_to_float4(rgb_to_y); + dscene->shaders.free(); + + if (scene->shaders.size() == 0) + return; + + KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size()); + bool has_volumes = false; + bool has_transparent_shadow = false; + + foreach (Shader *shader, scene->shaders) { + uint flag = 0; + + if (shader->use_mis) + flag |= SD_USE_MIS; + if (shader->has_surface_transparent && shader->use_transparent_shadow) + flag |= SD_HAS_TRANSPARENT_SHADOW; + if (shader->has_volume) { + flag |= SD_HAS_VOLUME; + has_volumes = true; + + /* todo: this could check more fine grained, to skip useless volumes + * enclosed inside an opaque bsdf. + */ + flag |= SD_HAS_TRANSPARENT_SHADOW; + } + /* in this case we can assume transparent surface */ + if (shader->has_volume_connected && !shader->has_surface) + flag |= SD_HAS_ONLY_VOLUME; + if (shader->heterogeneous_volume && shader->has_volume_spatial_varying) + flag |= SD_HETEROGENEOUS_VOLUME; + if (shader->has_attribute_dependency) + flag |= SD_NEED_ATTRIBUTES; + if (shader->has_bssrdf_bump) + flag |= SD_HAS_BSSRDF_BUMP; + if (device->info.has_volume_decoupled) { + if (shader->volume_sampling_method == VOLUME_SAMPLING_EQUIANGULAR) + flag |= SD_VOLUME_EQUIANGULAR; + if (shader->volume_sampling_method == VOLUME_SAMPLING_MULTIPLE_IMPORTANCE) + flag |= SD_VOLUME_MIS; + } + if (shader->volume_interpolation_method == VOLUME_INTERPOLATION_CUBIC) + flag |= SD_VOLUME_CUBIC; + if (shader->has_bump) + flag |= SD_HAS_BUMP; + if (shader->displacement_method != DISPLACE_BUMP) + flag |= SD_HAS_DISPLACEMENT; + + /* constant emission check */ + float3 constant_emission = make_float3(0.0f, 0.0f, 0.0f); + if (shader->is_constant_emission(&constant_emission)) + flag |= SD_HAS_CONSTANT_EMISSION; + + uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); + + /* regular shader */ + kshader->flags = flag; + kshader->pass_id = shader->pass_id; + kshader->constant_emission[0] = constant_emission.x; + kshader->constant_emission[1] = constant_emission.y; + kshader->constant_emission[2] = constant_emission.z; + kshader->cryptomatte_id = util_hash_to_float(cryptomatte_id); + kshader++; + + has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0; + } + + dscene->shaders.copy_to_device(); + + /* lookup tables */ + KernelTables *ktables = &dscene->data.tables; + + /* beckmann lookup table */ + if (beckmann_table_offset == TABLE_OFFSET_INVALID) { + if (!beckmann_table_ready) { + thread_scoped_lock lock(lookup_table_mutex); + if (!beckmann_table_ready) { + beckmann_table_build(beckmann_table); + beckmann_table_ready = true; + } + } + beckmann_table_offset = scene->lookup_tables->add_table(dscene, beckmann_table); + } + ktables->beckmann_offset = (int)beckmann_table_offset; + + /* integrator */ + KernelIntegrator *kintegrator = &dscene->data.integrator; + kintegrator->use_volumes = has_volumes; + /* TODO(sergey): De-duplicate with flags set in integrator.cpp. */ + kintegrator->transparent_shadows = has_transparent_shadow; + + /* film */ + KernelFilm *kfilm = &dscene->data.film; + /* color space, needs to be here because e.g. displacement shaders could depend on it */ + kfilm->xyz_to_r = float3_to_float4(xyz_to_r); + kfilm->xyz_to_g = float3_to_float4(xyz_to_g); + kfilm->xyz_to_b = float3_to_float4(xyz_to_b); + kfilm->rgb_to_y = float3_to_float4(rgb_to_y); } void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene) { - scene->lookup_tables->remove_table(&beckmann_table_offset); + scene->lookup_tables->remove_table(&beckmann_table_offset); - dscene->shaders.free(); + dscene->shaders.free(); } void ShaderManager::add_default(Scene *scene) { - /* default surface */ - { - ShaderGraph *graph = new ShaderGraph(); - - DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); - diffuse->color = make_float3(0.8f, 0.8f, 0.8f); - graph->add(diffuse); - - graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface")); - - Shader *shader = new Shader(); - shader->name = "default_surface"; - shader->graph = graph; - scene->shaders.push_back(shader); - scene->default_surface = shader; - } - - /* default light */ - { - ShaderGraph *graph = new ShaderGraph(); - - EmissionNode *emission = new EmissionNode(); - emission->color = make_float3(0.8f, 0.8f, 0.8f); - emission->strength = 0.0f; - graph->add(emission); - - graph->connect(emission->output("Emission"), graph->output()->input("Surface")); - - Shader *shader = new Shader(); - shader->name = "default_light"; - shader->graph = graph; - scene->shaders.push_back(shader); - scene->default_light = shader; - } - - /* default background */ - { - ShaderGraph *graph = new ShaderGraph(); - - Shader *shader = new Shader(); - shader->name = "default_background"; - shader->graph = graph; - scene->shaders.push_back(shader); - scene->default_background = shader; - } - - /* default empty */ - { - ShaderGraph *graph = new ShaderGraph(); - - Shader *shader = new Shader(); - shader->name = "default_empty"; - shader->graph = graph; - scene->shaders.push_back(shader); - scene->default_empty = shader; - } + /* default surface */ + { + ShaderGraph *graph = new ShaderGraph(); + + DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); + diffuse->color = make_float3(0.8f, 0.8f, 0.8f); + graph->add(diffuse); + + graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface")); + + Shader *shader = new Shader(); + shader->name = "default_surface"; + shader->graph = graph; + scene->shaders.push_back(shader); + scene->default_surface = shader; + } + + /* default light */ + { + ShaderGraph *graph = new ShaderGraph(); + + EmissionNode *emission = new EmissionNode(); + emission->color = make_float3(0.8f, 0.8f, 0.8f); + emission->strength = 0.0f; + graph->add(emission); + + graph->connect(emission->output("Emission"), graph->output()->input("Surface")); + + Shader *shader = new Shader(); + shader->name = "default_light"; + shader->graph = graph; + scene->shaders.push_back(shader); + scene->default_light = shader; + } + + /* default background */ + { + ShaderGraph *graph = new ShaderGraph(); + + Shader *shader = new Shader(); + shader->name = "default_background"; + shader->graph = graph; + scene->shaders.push_back(shader); + scene->default_background = shader; + } + + /* default empty */ + { + ShaderGraph *graph = new ShaderGraph(); + + Shader *shader = new Shader(); + shader->name = "default_empty"; + shader->graph = graph; + scene->shaders.push_back(shader); + scene->default_empty = shader; + } } void ShaderManager::get_requested_graph_features(ShaderGraph *graph, DeviceRequestedFeatures *requested_features) { - foreach(ShaderNode *node, graph->nodes) { - requested_features->max_nodes_group = max(requested_features->max_nodes_group, - node->get_group()); - requested_features->nodes_features |= node->get_feature(); - if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) { - BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode*>(node); - if(CLOSURE_IS_VOLUME(bsdf_node->closure)) { - requested_features->nodes_features |= NODE_FEATURE_VOLUME; - } - else if(CLOSURE_IS_PRINCIPLED(bsdf_node->closure)) { - requested_features->use_principled = true; - } - } - if(node->has_surface_bssrdf()) { - requested_features->use_subsurface = true; - } - if(node->has_surface_transparent()) { - requested_features->use_transparent = true; - } - if(node->has_raytrace()) { - requested_features->use_shader_raytrace = true; - } - } + foreach (ShaderNode *node, graph->nodes) { + requested_features->max_nodes_group = max(requested_features->max_nodes_group, + node->get_group()); + requested_features->nodes_features |= node->get_feature(); + if (node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) { + BsdfBaseNode *bsdf_node = static_cast<BsdfBaseNode *>(node); + if (CLOSURE_IS_VOLUME(bsdf_node->closure)) { + requested_features->nodes_features |= NODE_FEATURE_VOLUME; + } + else if (CLOSURE_IS_PRINCIPLED(bsdf_node->closure)) { + requested_features->use_principled = true; + } + } + if (node->has_surface_bssrdf()) { + requested_features->use_subsurface = true; + } + if (node->has_surface_transparent()) { + requested_features->use_transparent = true; + } + if (node->has_raytrace()) { + requested_features->use_shader_raytrace = true; + } + } } void ShaderManager::get_requested_features(Scene *scene, DeviceRequestedFeatures *requested_features) { - requested_features->max_nodes_group = NODE_GROUP_LEVEL_0; - requested_features->nodes_features = 0; - for(int i = 0; i < scene->shaders.size(); i++) { - Shader *shader = scene->shaders[i]; - /* Gather requested features from all the nodes from the graph nodes. */ - get_requested_graph_features(shader->graph, requested_features); - ShaderNode *output_node = shader->graph->output(); - if(output_node->input("Displacement")->link != NULL) { - requested_features->nodes_features |= NODE_FEATURE_BUMP; - if(shader->displacement_method == DISPLACE_BOTH) { - requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE; - } - } - /* On top of volume nodes, also check if we need volume sampling because - * e.g. an Emission node would slip through the NODE_FEATURE_VOLUME check */ - if(shader->has_volume) - requested_features->use_volume |= true; - } + requested_features->max_nodes_group = NODE_GROUP_LEVEL_0; + requested_features->nodes_features = 0; + for (int i = 0; i < scene->shaders.size(); i++) { + Shader *shader = scene->shaders[i]; + /* Gather requested features from all the nodes from the graph nodes. */ + get_requested_graph_features(shader->graph, requested_features); + ShaderNode *output_node = shader->graph->output(); + if (output_node->input("Displacement")->link != NULL) { + requested_features->nodes_features |= NODE_FEATURE_BUMP; + if (shader->displacement_method == DISPLACE_BOTH) { + requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE; + } + } + /* On top of volume nodes, also check if we need volume sampling because + * e.g. an Emission node would slip through the NODE_FEATURE_VOLUME check */ + if (shader->has_volume) + requested_features->use_volume |= true; + } } void ShaderManager::free_memory() { - beckmann_table.free_memory(); + beckmann_table.free_memory(); #ifdef WITH_OSL - OSLShaderManager::free_memory(); + OSLShaderManager::free_memory(); #endif } float ShaderManager::linear_rgb_to_gray(float3 c) { - return dot(c, rgb_to_y); + return dot(c, rgb_to_y); } string ShaderManager::get_cryptomatte_materials(Scene *scene) { - string manifest = "{"; - unordered_set<ustring, ustringHash> materials; - foreach(Shader *shader, scene->shaders) { - if(materials.count(shader->name)) { - continue; - } - materials.insert(shader->name); - uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); - manifest += string_printf("\"%s\":\"%08x\",", shader->name.c_str(), cryptomatte_id); - } - manifest[manifest.size()-1] = '}'; - return manifest; + string manifest = "{"; + unordered_set<ustring, ustringHash> materials; + foreach (Shader *shader, scene->shaders) { + if (materials.count(shader->name)) { + continue; + } + materials.insert(shader->name); + uint32_t cryptomatte_id = util_murmur_hash3(shader->name.c_str(), shader->name.length(), 0); + manifest += string_printf("\"%s\":\"%08x\",", shader->name.c_str(), cryptomatte_id); + } + manifest[manifest.size() - 1] = '}'; + return manifest; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index 05772b9a9cd..600b0cc59d4 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -45,33 +45,30 @@ class Scene; class ShaderGraph; struct float3; -enum ShadingSystem { - SHADINGSYSTEM_OSL, - SHADINGSYSTEM_SVM -}; +enum ShadingSystem { SHADINGSYSTEM_OSL, SHADINGSYSTEM_SVM }; /* Keep those in sync with the python-defined enum. */ enum VolumeSampling { - VOLUME_SAMPLING_DISTANCE = 0, - VOLUME_SAMPLING_EQUIANGULAR = 1, - VOLUME_SAMPLING_MULTIPLE_IMPORTANCE = 2, + VOLUME_SAMPLING_DISTANCE = 0, + VOLUME_SAMPLING_EQUIANGULAR = 1, + VOLUME_SAMPLING_MULTIPLE_IMPORTANCE = 2, - VOLUME_NUM_SAMPLING, + VOLUME_NUM_SAMPLING, }; enum VolumeInterpolation { - VOLUME_INTERPOLATION_LINEAR = 0, - VOLUME_INTERPOLATION_CUBIC = 1, + VOLUME_INTERPOLATION_LINEAR = 0, + VOLUME_INTERPOLATION_CUBIC = 1, - VOLUME_NUM_INTERPOLATION, + VOLUME_NUM_INTERPOLATION, }; enum DisplacementMethod { - DISPLACE_BUMP = 0, - DISPLACE_TRUE = 1, - DISPLACE_BOTH = 2, + DISPLACE_BUMP = 0, + DISPLACE_TRUE = 1, + DISPLACE_BOTH = 2, - DISPLACE_NUM_METHODS, + DISPLACE_NUM_METHODS, }; /* Shader describing the appearance of a Mesh, Light or Background. @@ -81,78 +78,78 @@ enum DisplacementMethod { * separately. */ class Shader : public Node { -public: - NODE_DECLARE - - int pass_id; - - /* shader graph */ - ShaderGraph *graph; - - /* sampling */ - bool use_mis; - bool use_transparent_shadow; - bool heterogeneous_volume; - VolumeSampling volume_sampling_method; - int volume_interpolation_method; - - /* synchronization */ - bool need_update; - bool need_update_mesh; - bool need_sync_object; - - /* If the shader has only volume components, the surface is assumed to - * be transparent. - * However, graph optimization might remove the volume subgraph, but - * since the user connected something to the volume output the surface - * should still be transparent. - * Therefore, has_volume_connected stores whether some volume subtree - * was connected before optimization. */ - bool has_volume_connected; - - /* information about shader after compiling */ - bool has_surface; - bool has_surface_emission; - bool has_surface_transparent; - bool has_volume; - bool has_displacement; - bool has_surface_bssrdf; - bool has_bump; - bool has_bssrdf_bump; - bool has_surface_spatial_varying; - bool has_volume_spatial_varying; - bool has_object_dependency; - bool has_attribute_dependency; - bool has_integrator_dependency; - - /* displacement */ - DisplacementMethod displacement_method; - - /* requested mesh attributes */ - AttributeRequestSet attributes; - - /* determined before compiling */ - uint id; - bool used; + public: + NODE_DECLARE + + int pass_id; + + /* shader graph */ + ShaderGraph *graph; + + /* sampling */ + bool use_mis; + bool use_transparent_shadow; + bool heterogeneous_volume; + VolumeSampling volume_sampling_method; + int volume_interpolation_method; + + /* synchronization */ + bool need_update; + bool need_update_mesh; + bool need_sync_object; + + /* If the shader has only volume components, the surface is assumed to + * be transparent. + * However, graph optimization might remove the volume subgraph, but + * since the user connected something to the volume output the surface + * should still be transparent. + * Therefore, has_volume_connected stores whether some volume subtree + * was connected before optimization. */ + bool has_volume_connected; + + /* information about shader after compiling */ + bool has_surface; + bool has_surface_emission; + bool has_surface_transparent; + bool has_volume; + bool has_displacement; + bool has_surface_bssrdf; + bool has_bump; + bool has_bssrdf_bump; + bool has_surface_spatial_varying; + bool has_volume_spatial_varying; + bool has_object_dependency; + bool has_attribute_dependency; + bool has_integrator_dependency; + + /* displacement */ + DisplacementMethod displacement_method; + + /* requested mesh attributes */ + AttributeRequestSet attributes; + + /* determined before compiling */ + uint id; + bool used; #ifdef WITH_OSL - /* osl shading state references */ - OSL::ShaderGroupRef osl_surface_ref; - OSL::ShaderGroupRef osl_surface_bump_ref; - OSL::ShaderGroupRef osl_volume_ref; - OSL::ShaderGroupRef osl_displacement_ref; + /* osl shading state references */ + OSL::ShaderGroupRef osl_surface_ref; + OSL::ShaderGroupRef osl_surface_bump_ref; + OSL::ShaderGroupRef osl_volume_ref; + OSL::ShaderGroupRef osl_displacement_ref; #endif - Shader(); - ~Shader(); + Shader(); + ~Shader(); - /* Checks whether the shader consists of just a emission node with fixed inputs that's connected directly to the output. - * If yes, it sets the content of emission to the constant value (color * strength), which is then used for speeding up light evaluation. */ - bool is_constant_emission(float3* emission); + /* Checks whether the shader consists of just a emission node with fixed inputs that's connected directly to the output. + * If yes, it sets the content of emission to the constant value (color * strength), which is then used for speeding up light evaluation. */ + bool is_constant_emission(float3 *emission); - void set_graph(ShaderGraph *graph); - void tag_update(Scene *scene); - void tag_used(Scene *scene); + void set_graph(ShaderGraph *graph); + void tag_update(Scene *scene); + void tag_used(Scene *scene); }; /* Shader Manager virtual base class @@ -161,68 +158,73 @@ public: * shader compiling and device updating. */ class ShaderManager { -public: - bool need_update; + public: + bool need_update; - static ShaderManager *create(Scene *scene, int shadingsystem); - virtual ~ShaderManager(); + static ShaderManager *create(Scene *scene, int shadingsystem); + virtual ~ShaderManager(); - virtual void reset(Scene *scene) = 0; + virtual void reset(Scene *scene) = 0; - virtual bool use_osl() { return false; } + virtual bool use_osl() + { + return false; + } - /* device update */ - virtual void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) = 0; - virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0; + /* device update */ + virtual void device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) = 0; + virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0; - void device_update_shaders_used(Scene *scene); - void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_free_common(Device *device, DeviceScene *dscene, Scene *scene); + void device_update_shaders_used(Scene *scene); + void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free_common(Device *device, DeviceScene *dscene, Scene *scene); - /* get globally unique id for a type of attribute */ - uint get_attribute_id(ustring name); - uint get_attribute_id(AttributeStandard std); + /* get globally unique id for a type of attribute */ + uint get_attribute_id(ustring name); + uint get_attribute_id(AttributeStandard std); - /* get shader id for mesh faces */ - int get_shader_id(Shader *shader, bool smooth = false); + /* get shader id for mesh faces */ + int get_shader_id(Shader *shader, bool smooth = false); - /* add default shaders to scene, to use as default for things that don't - * have any shader assigned explicitly */ - static void add_default(Scene *scene); + /* add default shaders to scene, to use as default for things that don't + * have any shader assigned explicitly */ + static void add_default(Scene *scene); - /* Selective nodes compilation. */ - void get_requested_features(Scene *scene, - DeviceRequestedFeatures *requested_features); + /* Selective nodes compilation. */ + void get_requested_features(Scene *scene, DeviceRequestedFeatures *requested_features); - static void free_memory(); + static void free_memory(); - float linear_rgb_to_gray(float3 c); + float linear_rgb_to_gray(float3 c); - string get_cryptomatte_materials(Scene *scene); + string get_cryptomatte_materials(Scene *scene); -protected: - ShaderManager(); + protected: + ShaderManager(); - typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap; - AttributeIDMap unique_attribute_id; + typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap; + AttributeIDMap unique_attribute_id; - static thread_mutex lookup_table_mutex; - static vector<float> beckmann_table; - static bool beckmann_table_ready; + static thread_mutex lookup_table_mutex; + static vector<float> beckmann_table; + static bool beckmann_table_ready; - size_t beckmann_table_offset; + size_t beckmann_table_offset; - void get_requested_graph_features(ShaderGraph *graph, - DeviceRequestedFeatures *requested_features); + void get_requested_graph_features(ShaderGraph *graph, + DeviceRequestedFeatures *requested_features); - thread_spin_lock attribute_lock_; + thread_spin_lock attribute_lock_; - float3 xyz_to_r; - float3 xyz_to_g; - float3 xyz_to_b; - float3 rgb_to_y; + float3 xyz_to_r; + float3 xyz_to_g; + float3 xyz_to_b; + float3 rgb_to_y; }; CCL_NAMESPACE_END -#endif /* __SHADER_H__ */ +#endif /* __SHADER_H__ */ diff --git a/intern/cycles/render/sobol.h b/intern/cycles/render/sobol.h index ce7a28587f2..d38857d2b35 100644 --- a/intern/cycles/render/sobol.h +++ b/intern/cycles/render/sobol.h @@ -28,4 +28,4 @@ void sobol_generate_direction_vectors(uint vectors[][SOBOL_BITS], int dimensions CCL_NAMESPACE_END -#endif /* __SOBOL_H__ */ +#endif /* __SOBOL_H__ */ diff --git a/intern/cycles/render/stats.cpp b/intern/cycles/render/stats.cpp index 4245745944d..0937b95a891 100644 --- a/intern/cycles/render/stats.cpp +++ b/intern/cycles/render/stats.cpp @@ -28,284 +28,293 @@ static int kIndentNumSpaces = 2; namespace { -bool namedSizeEntryComparator(const NamedSizeEntry& a, const NamedSizeEntry& b) +bool namedSizeEntryComparator(const NamedSizeEntry &a, const NamedSizeEntry &b) { - /* We sort in descending order. */ - return a.size > b.size; + /* We sort in descending order. */ + return a.size > b.size; } -bool namedTimeSampleEntryComparator(const NamedNestedSampleStats& a, const NamedNestedSampleStats& b) +bool namedTimeSampleEntryComparator(const NamedNestedSampleStats &a, + const NamedNestedSampleStats &b) { - return a.sum_samples > b.sum_samples; + return a.sum_samples > b.sum_samples; } -bool namedSampleCountPairComparator(const NamedSampleCountPair& a, const NamedSampleCountPair& b) +bool namedSampleCountPairComparator(const NamedSampleCountPair &a, const NamedSampleCountPair &b) { - return a.samples > b.samples; + return a.samples > b.samples; } } // namespace -NamedSizeEntry::NamedSizeEntry() - : name(""), - size(0) { +NamedSizeEntry::NamedSizeEntry() : name(""), size(0) +{ } -NamedSizeEntry::NamedSizeEntry(const string& name, size_t size) - : name(name), - size(size) { +NamedSizeEntry::NamedSizeEntry(const string &name, size_t size) : name(name), size(size) +{ } /* Named size statistics. */ -NamedSizeStats::NamedSizeStats() - : total_size(0) { +NamedSizeStats::NamedSizeStats() : total_size(0) +{ } -void NamedSizeStats::add_entry(const NamedSizeEntry& entry) { - total_size += entry.size; - entries.push_back(entry); +void NamedSizeStats::add_entry(const NamedSizeEntry &entry) +{ + total_size += entry.size; + entries.push_back(entry); } string NamedSizeStats::full_report(int indent_level) { - const string indent(indent_level * kIndentNumSpaces, ' '); - const string double_indent = indent + indent; - string result = ""; - result += string_printf("%sTotal memory: %s (%s)\n", - indent.c_str(), - string_human_readable_size(total_size).c_str(), - string_human_readable_number(total_size).c_str()); - sort(entries.begin(), entries.end(), namedSizeEntryComparator); - foreach(const NamedSizeEntry& entry, entries) { - result += string_printf( - "%s%-32s %s (%s)\n", - double_indent.c_str(), - entry.name.c_str(), - string_human_readable_size(entry.size).c_str(), - string_human_readable_number(entry.size).c_str()); - } - return result; + const string indent(indent_level * kIndentNumSpaces, ' '); + const string double_indent = indent + indent; + string result = ""; + result += string_printf("%sTotal memory: %s (%s)\n", + indent.c_str(), + string_human_readable_size(total_size).c_str(), + string_human_readable_number(total_size).c_str()); + sort(entries.begin(), entries.end(), namedSizeEntryComparator); + foreach (const NamedSizeEntry &entry, entries) { + result += string_printf("%s%-32s %s (%s)\n", + double_indent.c_str(), + entry.name.c_str(), + string_human_readable_size(entry.size).c_str(), + string_human_readable_number(entry.size).c_str()); + } + return result; } /* Named time sample statistics. */ -NamedNestedSampleStats::NamedNestedSampleStats() - : name(""), self_samples(0), sum_samples(0) -{} +NamedNestedSampleStats::NamedNestedSampleStats() : name(""), self_samples(0), sum_samples(0) +{ +} -NamedNestedSampleStats::NamedNestedSampleStats(const string& name, uint64_t samples) - : name(name), self_samples(samples), sum_samples(samples) -{} +NamedNestedSampleStats::NamedNestedSampleStats(const string &name, uint64_t samples) + : name(name), self_samples(samples), sum_samples(samples) +{ +} -NamedNestedSampleStats& NamedNestedSampleStats::add_entry(const string& name_, uint64_t samples_) +NamedNestedSampleStats &NamedNestedSampleStats::add_entry(const string &name_, uint64_t samples_) { - entries.push_back(NamedNestedSampleStats(name_, samples_)); - return entries[entries.size()-1]; + entries.push_back(NamedNestedSampleStats(name_, samples_)); + return entries[entries.size() - 1]; } void NamedNestedSampleStats::update_sum() { - sum_samples = self_samples; - foreach(NamedNestedSampleStats& entry, entries) { - entry.update_sum(); - sum_samples += entry.sum_samples; - } + sum_samples = self_samples; + foreach (NamedNestedSampleStats &entry, entries) { + entry.update_sum(); + sum_samples += entry.sum_samples; + } } string NamedNestedSampleStats::full_report(int indent_level, uint64_t total_samples) { - update_sum(); - - if(total_samples == 0) { - total_samples = sum_samples; - } - - const string indent(indent_level * kIndentNumSpaces, ' '); - - const double sum_percent = 100*((double) sum_samples) / total_samples; - const double sum_seconds = sum_samples * 0.001; - const double self_percent = 100*((double) self_samples) / total_samples; - const double self_seconds = self_samples * 0.001; - string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n", - name.c_str(), - sum_percent, - sum_seconds, - self_percent, - self_seconds); - string result = indent + info; - - sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator); - foreach(NamedNestedSampleStats& entry, entries) { - result += entry.full_report(indent_level + 1, total_samples); - } - return result; + update_sum(); + + if (total_samples == 0) { + total_samples = sum_samples; + } + + const string indent(indent_level * kIndentNumSpaces, ' '); + + const double sum_percent = 100 * ((double)sum_samples) / total_samples; + const double sum_seconds = sum_samples * 0.001; + const double self_percent = 100 * ((double)self_samples) / total_samples; + const double self_seconds = self_samples * 0.001; + string info = string_printf("%-32s: Total %3.2f%% (%.2fs), Self %3.2f%% (%.2fs)\n", + name.c_str(), + sum_percent, + sum_seconds, + self_percent, + self_seconds); + string result = indent + info; + + sort(entries.begin(), entries.end(), namedTimeSampleEntryComparator); + foreach (NamedNestedSampleStats &entry, entries) { + result += entry.full_report(indent_level + 1, total_samples); + } + return result; } /* Named sample count pairs. */ -NamedSampleCountPair::NamedSampleCountPair(const ustring& name, uint64_t samples, uint64_t hits) - : name(name), samples(samples), hits(hits) -{} +NamedSampleCountPair::NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits) + : name(name), samples(samples), hits(hits) +{ +} NamedSampleCountStats::NamedSampleCountStats() -{} +{ +} -void NamedSampleCountStats::add(const ustring& name, uint64_t samples, uint64_t hits) +void NamedSampleCountStats::add(const ustring &name, uint64_t samples, uint64_t hits) { - entry_map::iterator entry = entries.find(name); - if(entry != entries.end()) { - entry->second.samples += samples; - entry->second.hits += hits; - return; - } - entries.emplace(name, NamedSampleCountPair(name, samples, hits)); + entry_map::iterator entry = entries.find(name); + if (entry != entries.end()) { + entry->second.samples += samples; + entry->second.hits += hits; + return; + } + entries.emplace(name, NamedSampleCountPair(name, samples, hits)); } string NamedSampleCountStats::full_report(int indent_level) { - const string indent(indent_level * kIndentNumSpaces, ' '); + const string indent(indent_level * kIndentNumSpaces, ' '); - vector<NamedSampleCountPair> sorted_entries; - sorted_entries.reserve(entries.size()); + vector<NamedSampleCountPair> sorted_entries; + sorted_entries.reserve(entries.size()); - uint64_t total_hits = 0, total_samples = 0; - foreach(entry_map::const_reference entry, entries) { - const NamedSampleCountPair &pair = entry.second; + uint64_t total_hits = 0, total_samples = 0; + foreach (entry_map::const_reference entry, entries) { + const NamedSampleCountPair &pair = entry.second; - total_hits += pair.hits; - total_samples += pair.samples; + total_hits += pair.hits; + total_samples += pair.samples; - sorted_entries.push_back(pair); - } - const double avg_samples_per_hit = ((double) total_samples) / total_hits; + sorted_entries.push_back(pair); + } + const double avg_samples_per_hit = ((double)total_samples) / total_hits; - sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator); + sort(sorted_entries.begin(), sorted_entries.end(), namedSampleCountPairComparator); - string result = ""; - foreach(const NamedSampleCountPair& entry, sorted_entries) { - const double seconds = entry.samples * 0.001; - const double relative = ((double) entry.samples) / (entry.hits * avg_samples_per_hit); + string result = ""; + foreach (const NamedSampleCountPair &entry, sorted_entries) { + const double seconds = entry.samples * 0.001; + const double relative = ((double)entry.samples) / (entry.hits * avg_samples_per_hit); - result += indent + string_printf("%-32s: %.2fs (Relative cost: %.2f)\n", - entry.name.c_str(), - seconds, - relative); - } - return result; + result += indent + + string_printf( + "%-32s: %.2fs (Relative cost: %.2f)\n", entry.name.c_str(), seconds, relative); + } + return result; } /* Mesh statistics. */ -MeshStats::MeshStats() { +MeshStats::MeshStats() +{ } string MeshStats::full_report(int indent_level) { - const string indent(indent_level * kIndentNumSpaces, ' '); - string result = ""; - result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1); - return result; + const string indent(indent_level * kIndentNumSpaces, ' '); + string result = ""; + result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1); + return result; } /* Image statistics. */ -ImageStats::ImageStats() { +ImageStats::ImageStats() +{ } string ImageStats::full_report(int indent_level) { - const string indent(indent_level * kIndentNumSpaces, ' '); - string result = ""; - result += indent + "Textures:\n" + textures.full_report(indent_level + 1); - return result; + const string indent(indent_level * kIndentNumSpaces, ' '); + string result = ""; + result += indent + "Textures:\n" + textures.full_report(indent_level + 1); + return result; } /* Overall statistics. */ -RenderStats::RenderStats() { - has_profiling = false; +RenderStats::RenderStats() +{ + has_profiling = false; } -void RenderStats::collect_profiling(Scene *scene, Profiler& prof) +void RenderStats::collect_profiling(Scene *scene, Profiler &prof) { - has_profiling = true; - - kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN)); - - kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP)); - kernel.add_entry("Result writing", prof.get_event(PROFILING_WRITE_RESULT)); - - NamedNestedSampleStats &integrator = kernel.add_entry("Path integration", prof.get_event(PROFILING_PATH_INTEGRATE)); - integrator.add_entry("Scene intersection", prof.get_event(PROFILING_SCENE_INTERSECT)); - integrator.add_entry("Indirect emission", prof.get_event(PROFILING_INDIRECT_EMISSION)); - integrator.add_entry("Volumes", prof.get_event(PROFILING_VOLUME)); - - NamedNestedSampleStats &shading = integrator.add_entry("Shading", 0); - shading.add_entry("Shader Setup", prof.get_event(PROFILING_SHADER_SETUP)); - shading.add_entry("Shader Eval", prof.get_event(PROFILING_SHADER_EVAL)); - shading.add_entry("Shader Apply", prof.get_event(PROFILING_SHADER_APPLY)); - shading.add_entry("Ambient Occlusion", prof.get_event(PROFILING_AO)); - shading.add_entry("Subsurface", prof.get_event(PROFILING_SUBSURFACE)); - - integrator.add_entry("Connect Light", prof.get_event(PROFILING_CONNECT_LIGHT)); - integrator.add_entry("Surface Bounce", prof.get_event(PROFILING_SURFACE_BOUNCE)); - - NamedNestedSampleStats &intersection = kernel.add_entry("Intersection", 0); - intersection.add_entry("Full Intersection", prof.get_event(PROFILING_INTERSECT)); - intersection.add_entry("Local Intersection", prof.get_event(PROFILING_INTERSECT_LOCAL)); - intersection.add_entry("Shadow All Intersection", prof.get_event(PROFILING_INTERSECT_SHADOW_ALL)); - intersection.add_entry("Volume Intersection", prof.get_event(PROFILING_INTERSECT_VOLUME)); - intersection.add_entry("Volume All Intersection", prof.get_event(PROFILING_INTERSECT_VOLUME_ALL)); - - NamedNestedSampleStats &closure = kernel.add_entry("Closures", 0); - closure.add_entry("Surface Closure Evaluation", prof.get_event(PROFILING_CLOSURE_EVAL)); - closure.add_entry("Surface Closure Sampling", prof.get_event(PROFILING_CLOSURE_SAMPLE)); - closure.add_entry("Volume Closure Evaluation", prof.get_event(PROFILING_CLOSURE_VOLUME_EVAL)); - closure.add_entry("Volume Closure Sampling", prof.get_event(PROFILING_CLOSURE_VOLUME_SAMPLE)); - - NamedNestedSampleStats &denoising = kernel.add_entry("Denoising", prof.get_event(PROFILING_DENOISING)); - denoising.add_entry("Construct Transform", prof.get_event(PROFILING_DENOISING_CONSTRUCT_TRANSFORM)); - denoising.add_entry("Reconstruct", prof.get_event(PROFILING_DENOISING_RECONSTRUCT)); - - NamedNestedSampleStats &prefilter = denoising.add_entry("Prefiltering", 0); - prefilter.add_entry("Divide Shadow", prof.get_event(PROFILING_DENOISING_DIVIDE_SHADOW)); - prefilter.add_entry("Non-Local means", prof.get_event(PROFILING_DENOISING_NON_LOCAL_MEANS)); - prefilter.add_entry("Get Feature", prof.get_event(PROFILING_DENOISING_GET_FEATURE)); - prefilter.add_entry("Detect Outliers", prof.get_event(PROFILING_DENOISING_DETECT_OUTLIERS)); - prefilter.add_entry("Combine Halves", prof.get_event(PROFILING_DENOISING_COMBINE_HALVES)); - - shaders.entries.clear(); - foreach(Shader *shader, scene->shaders) { - uint64_t samples, hits; - if(prof.get_shader(shader->id, samples, hits)) { - shaders.add(shader->name, samples, hits); - } - } - - objects.entries.clear(); - foreach(Object *object, scene->objects) { - uint64_t samples, hits; - if(prof.get_object(object->get_device_index(), samples, hits)) { - objects.add(object->name, samples, hits); - } - } + has_profiling = true; + + kernel = NamedNestedSampleStats("Total render time", prof.get_event(PROFILING_UNKNOWN)); + + kernel.add_entry("Ray setup", prof.get_event(PROFILING_RAY_SETUP)); + kernel.add_entry("Result writing", prof.get_event(PROFILING_WRITE_RESULT)); + + NamedNestedSampleStats &integrator = kernel.add_entry("Path integration", + prof.get_event(PROFILING_PATH_INTEGRATE)); + integrator.add_entry("Scene intersection", prof.get_event(PROFILING_SCENE_INTERSECT)); + integrator.add_entry("Indirect emission", prof.get_event(PROFILING_INDIRECT_EMISSION)); + integrator.add_entry("Volumes", prof.get_event(PROFILING_VOLUME)); + + NamedNestedSampleStats &shading = integrator.add_entry("Shading", 0); + shading.add_entry("Shader Setup", prof.get_event(PROFILING_SHADER_SETUP)); + shading.add_entry("Shader Eval", prof.get_event(PROFILING_SHADER_EVAL)); + shading.add_entry("Shader Apply", prof.get_event(PROFILING_SHADER_APPLY)); + shading.add_entry("Ambient Occlusion", prof.get_event(PROFILING_AO)); + shading.add_entry("Subsurface", prof.get_event(PROFILING_SUBSURFACE)); + + integrator.add_entry("Connect Light", prof.get_event(PROFILING_CONNECT_LIGHT)); + integrator.add_entry("Surface Bounce", prof.get_event(PROFILING_SURFACE_BOUNCE)); + + NamedNestedSampleStats &intersection = kernel.add_entry("Intersection", 0); + intersection.add_entry("Full Intersection", prof.get_event(PROFILING_INTERSECT)); + intersection.add_entry("Local Intersection", prof.get_event(PROFILING_INTERSECT_LOCAL)); + intersection.add_entry("Shadow All Intersection", + prof.get_event(PROFILING_INTERSECT_SHADOW_ALL)); + intersection.add_entry("Volume Intersection", prof.get_event(PROFILING_INTERSECT_VOLUME)); + intersection.add_entry("Volume All Intersection", + prof.get_event(PROFILING_INTERSECT_VOLUME_ALL)); + + NamedNestedSampleStats &closure = kernel.add_entry("Closures", 0); + closure.add_entry("Surface Closure Evaluation", prof.get_event(PROFILING_CLOSURE_EVAL)); + closure.add_entry("Surface Closure Sampling", prof.get_event(PROFILING_CLOSURE_SAMPLE)); + closure.add_entry("Volume Closure Evaluation", prof.get_event(PROFILING_CLOSURE_VOLUME_EVAL)); + closure.add_entry("Volume Closure Sampling", prof.get_event(PROFILING_CLOSURE_VOLUME_SAMPLE)); + + NamedNestedSampleStats &denoising = kernel.add_entry("Denoising", + prof.get_event(PROFILING_DENOISING)); + denoising.add_entry("Construct Transform", + prof.get_event(PROFILING_DENOISING_CONSTRUCT_TRANSFORM)); + denoising.add_entry("Reconstruct", prof.get_event(PROFILING_DENOISING_RECONSTRUCT)); + + NamedNestedSampleStats &prefilter = denoising.add_entry("Prefiltering", 0); + prefilter.add_entry("Divide Shadow", prof.get_event(PROFILING_DENOISING_DIVIDE_SHADOW)); + prefilter.add_entry("Non-Local means", prof.get_event(PROFILING_DENOISING_NON_LOCAL_MEANS)); + prefilter.add_entry("Get Feature", prof.get_event(PROFILING_DENOISING_GET_FEATURE)); + prefilter.add_entry("Detect Outliers", prof.get_event(PROFILING_DENOISING_DETECT_OUTLIERS)); + prefilter.add_entry("Combine Halves", prof.get_event(PROFILING_DENOISING_COMBINE_HALVES)); + + shaders.entries.clear(); + foreach (Shader *shader, scene->shaders) { + uint64_t samples, hits; + if (prof.get_shader(shader->id, samples, hits)) { + shaders.add(shader->name, samples, hits); + } + } + + objects.entries.clear(); + foreach (Object *object, scene->objects) { + uint64_t samples, hits; + if (prof.get_object(object->get_device_index(), samples, hits)) { + objects.add(object->name, samples, hits); + } + } } string RenderStats::full_report() { - string result = ""; - result += "Mesh statistics:\n" + mesh.full_report(1); - result += "Image statistics:\n" + image.full_report(1); - if(has_profiling) { - result += "Kernel statistics:\n" + kernel.full_report(1); - result += "Shader statistics:\n" + shaders.full_report(1); - result += "Object statistics:\n" + objects.full_report(1); - } - else { - result += "Profiling information not available (only works with CPU rendering)"; - } - return result; + string result = ""; + result += "Mesh statistics:\n" + mesh.full_report(1); + result += "Image statistics:\n" + image.full_report(1); + if (has_profiling) { + result += "Kernel statistics:\n" + kernel.full_report(1); + result += "Shader statistics:\n" + shaders.full_report(1); + result += "Object statistics:\n" + objects.full_report(1); + } + else { + result += "Profiling information not available (only works with CPU rendering)"; + } + return result; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/stats.h b/intern/cycles/render/stats.h index 33fe1f4b185..f1bf1903483 100644 --- a/intern/cycles/render/stats.h +++ b/intern/cycles/render/stats.h @@ -33,12 +33,12 @@ CCL_NAMESPACE_BEGIN * avoiding duplicating code for things like sorting. */ class NamedSizeEntry { -public: - NamedSizeEntry(); - NamedSizeEntry(const string& name, size_t size); + public: + NamedSizeEntry(); + NamedSizeEntry(const string &name, size_t size); - string name; - size_t size; + string name; + size_t size; }; /* Container of named size entries. Used, for example, to store per-mesh memory @@ -46,115 +46,115 @@ public: * container. */ class NamedSizeStats { -public: - NamedSizeStats(); + public: + NamedSizeStats(); - /* Add entry to the statistics. */ - void add_entry(const NamedSizeEntry& entry); + /* Add entry to the statistics. */ + void add_entry(const NamedSizeEntry &entry); - /* Generate full human-readable report. */ - string full_report(int indent_level = 0); + /* Generate full human-readable report. */ + string full_report(int indent_level = 0); - /* Total size of all entries. */ - size_t total_size; + /* Total size of all entries. */ + size_t total_size; - /* NOTE: Is fine to read directly, but for adding use add_entry(), which - * makes sure all accumulating values are properly updated. - */ - vector<NamedSizeEntry> entries; + /* NOTE: Is fine to read directly, but for adding use add_entry(), which + * makes sure all accumulating values are properly updated. + */ + vector<NamedSizeEntry> entries; }; class NamedNestedSampleStats { -public: - NamedNestedSampleStats(); - NamedNestedSampleStats(const string& name, uint64_t samples); + public: + NamedNestedSampleStats(); + NamedNestedSampleStats(const string &name, uint64_t samples); - NamedNestedSampleStats& add_entry(const string& name, uint64_t samples); + NamedNestedSampleStats &add_entry(const string &name, uint64_t samples); - /* Updates sum_samples recursively. */ - void update_sum(); + /* Updates sum_samples recursively. */ + void update_sum(); - string full_report(int indent_level = 0, uint64_t total_samples = 0); + string full_report(int indent_level = 0, uint64_t total_samples = 0); - string name; + string name; - /* self_samples contains only the samples that this specific event got, - * while sum_samples also includes the samples of all sub-entries. */ - uint64_t self_samples, sum_samples; + /* self_samples contains only the samples that this specific event got, + * while sum_samples also includes the samples of all sub-entries. */ + uint64_t self_samples, sum_samples; - vector<NamedNestedSampleStats> entries; + vector<NamedNestedSampleStats> entries; }; /* Named entry containing both a time-sample count for objects of a type and a * total count of processed items. * This allows to estimate the time spent per item. */ class NamedSampleCountPair { -public: - NamedSampleCountPair(const ustring& name, uint64_t samples, uint64_t hits); + public: + NamedSampleCountPair(const ustring &name, uint64_t samples, uint64_t hits); - ustring name; - uint64_t samples; - uint64_t hits; + ustring name; + uint64_t samples; + uint64_t hits; }; /* Contains statistics about pairs of samples and counts as described above. */ class NamedSampleCountStats { -public: - NamedSampleCountStats(); + public: + NamedSampleCountStats(); - string full_report(int indent_level = 0); - void add(const ustring& name, uint64_t samples, uint64_t hits); + string full_report(int indent_level = 0); + void add(const ustring &name, uint64_t samples, uint64_t hits); - typedef unordered_map<ustring, NamedSampleCountPair, ustringHash> entry_map; - entry_map entries; + typedef unordered_map<ustring, NamedSampleCountPair, ustringHash> entry_map; + entry_map entries; }; /* Statistics about mesh in the render database. */ class MeshStats { -public: - MeshStats(); + public: + MeshStats(); - /* Generate full human-readable report. */ - string full_report(int indent_level = 0); + /* Generate full human-readable report. */ + string full_report(int indent_level = 0); - /* Input geometry statistics, this is what is coming as an input to render - * from. say, Blender. This does not include runtime or engine specific - * memory like BVH. - */ - NamedSizeStats geometry; + /* Input geometry statistics, this is what is coming as an input to render + * from. say, Blender. This does not include runtime or engine specific + * memory like BVH. + */ + NamedSizeStats geometry; }; /* Statistics about images held in memory. */ class ImageStats { -public: - ImageStats(); + public: + ImageStats(); - /* Generate full human-readable report. */ - string full_report(int indent_level = 0); + /* Generate full human-readable report. */ + string full_report(int indent_level = 0); - NamedSizeStats textures; + NamedSizeStats textures; }; /* Render process statistics. */ class RenderStats { -public: - RenderStats(); + public: + RenderStats(); - /* Return full report as string. */ - string full_report(); + /* Return full report as string. */ + string full_report(); - /* Collect kernel sampling information from Stats. */ - void collect_profiling(Scene *scene, Profiler& prof); + /* Collect kernel sampling information from Stats. */ + void collect_profiling(Scene *scene, Profiler &prof); - bool has_profiling; + bool has_profiling; - MeshStats mesh; - ImageStats image; - NamedNestedSampleStats kernel; - NamedSampleCountStats shaders; - NamedSampleCountStats objects; + MeshStats mesh; + ImageStats image; + NamedNestedSampleStats kernel; + NamedSampleCountStats shaders; + NamedSampleCountStats objects; }; CCL_NAMESPACE_END -#endif /* __RENDER_STATS_H__ */ +#endif /* __RENDER_STATS_H__ */ diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 360b2b461cf..d8e3e24f39e 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -49,107 +49,106 @@ void SVMShaderManager::device_update_shader(Scene *scene, Progress *progress, array<int4> *global_svm_nodes) { - if(progress->get_cancel()) { - return; - } - assert(shader->graph); + if (progress->get_cancel()) { + return; + } + assert(shader->graph); - array<int4> svm_nodes; - svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); + array<int4> svm_nodes; + svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); - SVMCompiler::Summary summary; - SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager); - compiler.background = (shader == scene->default_background); - compiler.compile(scene, shader, svm_nodes, 0, &summary); + SVMCompiler::Summary summary; + SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager); + compiler.background = (shader == scene->default_background); + compiler.compile(scene, shader, svm_nodes, 0, &summary); - VLOG(2) << "Compilation summary:\n" - << "Shader name: " << shader->name << "\n" - << summary.full_report(); + VLOG(2) << "Compilation summary:\n" + << "Shader name: " << shader->name << "\n" + << summary.full_report(); - nodes_lock_.lock(); - if(shader->use_mis && shader->has_surface_emission) { - scene->light_manager->need_update = true; - } + nodes_lock_.lock(); + if (shader->use_mis && shader->has_surface_emission) { + scene->light_manager->need_update = true; + } - /* The copy needs to be done inside the lock, if another thread resizes the array - * while memcpy is running, it'll be copying into possibly invalid/freed ram. - */ - size_t global_nodes_size = global_svm_nodes->size(); - global_svm_nodes->resize(global_nodes_size + svm_nodes.size()); + /* The copy needs to be done inside the lock, if another thread resizes the array + * while memcpy is running, it'll be copying into possibly invalid/freed ram. + */ + size_t global_nodes_size = global_svm_nodes->size(); + global_svm_nodes->resize(global_nodes_size + svm_nodes.size()); - /* Offset local SVM nodes to a global address space. */ - int4& jump_node = (*global_svm_nodes)[shader->id]; - jump_node.y = svm_nodes[0].y + global_nodes_size - 1; - jump_node.z = svm_nodes[0].z + global_nodes_size - 1; - jump_node.w = svm_nodes[0].w + global_nodes_size - 1; - /* Copy new nodes to global storage. */ - memcpy(&(*global_svm_nodes)[global_nodes_size], - &svm_nodes[1], - sizeof(int4) * (svm_nodes.size() - 1)); - nodes_lock_.unlock(); + /* Offset local SVM nodes to a global address space. */ + int4 &jump_node = (*global_svm_nodes)[shader->id]; + jump_node.y = svm_nodes[0].y + global_nodes_size - 1; + jump_node.z = svm_nodes[0].z + global_nodes_size - 1; + jump_node.w = svm_nodes[0].w + global_nodes_size - 1; + /* Copy new nodes to global storage. */ + memcpy(&(*global_svm_nodes)[global_nodes_size], + &svm_nodes[1], + sizeof(int4) * (svm_nodes.size() - 1)); + nodes_lock_.unlock(); } -void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void SVMShaderManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) { - if(!need_update) - return; + if (!need_update) + return; - VLOG(1) << "Total " << scene->shaders.size() << " shaders."; + VLOG(1) << "Total " << scene->shaders.size() << " shaders."; - double start_time = time_dt(); + double start_time = time_dt(); - /* test if we need to update */ - device_free(device, dscene, scene); + /* test if we need to update */ + device_free(device, dscene, scene); - /* determine which shaders are in use */ - device_update_shaders_used(scene); + /* determine which shaders are in use */ + device_update_shaders_used(scene); - /* svm_nodes */ - array<int4> svm_nodes; - size_t i; + /* svm_nodes */ + array<int4> svm_nodes; + size_t i; - for(i = 0; i < scene->shaders.size(); i++) { - svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); - } + for (i = 0; i < scene->shaders.size(); i++) { + svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); + } - TaskPool task_pool; - foreach(Shader *shader, scene->shaders) { - task_pool.push(function_bind(&SVMShaderManager::device_update_shader, - this, - scene, - shader, - &progress, - &svm_nodes), - false); - } - task_pool.wait_work(); + TaskPool task_pool; + foreach (Shader *shader, scene->shaders) { + task_pool.push( + function_bind( + &SVMShaderManager::device_update_shader, this, scene, shader, &progress, &svm_nodes), + false); + } + task_pool.wait_work(); - if(progress.get_cancel()) { - return; - } + if (progress.get_cancel()) { + return; + } - dscene->svm_nodes.steal_data(svm_nodes); - dscene->svm_nodes.copy_to_device(); + dscene->svm_nodes.steal_data(svm_nodes); + dscene->svm_nodes.copy_to_device(); - for(i = 0; i < scene->shaders.size(); i++) { - Shader *shader = scene->shaders[i]; - shader->need_update = false; - } + for (i = 0; i < scene->shaders.size(); i++) { + Shader *shader = scene->shaders[i]; + shader->need_update = false; + } - device_update_common(device, dscene, scene, progress); + device_update_common(device, dscene, scene, progress); - need_update = false; + need_update = false; - VLOG(1) << "Shader manager updated " - << scene->shaders.size() << " shaders in " - << time_dt() - start_time << " seconds."; + VLOG(1) << "Shader manager updated " << scene->shaders.size() << " shaders in " + << time_dt() - start_time << " seconds."; } void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene) { - device_free_common(device, dscene, scene); + device_free_common(device, dscene, scene); - dscene->svm_nodes.free(); + dscene->svm_nodes.free(); } /* Graph Compiler */ @@ -158,772 +157,751 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_manager_, LightManager *light_manager_) { - shader_manager = shader_manager_; - image_manager = image_manager_; - light_manager = light_manager_; - max_stack_use = 0; - current_type = SHADER_TYPE_SURFACE; - current_shader = NULL; - current_graph = NULL; - background = false; - mix_weight_offset = SVM_STACK_INVALID; - compile_failed = false; + shader_manager = shader_manager_; + image_manager = image_manager_; + light_manager = light_manager_; + max_stack_use = 0; + current_type = SHADER_TYPE_SURFACE; + current_shader = NULL; + current_graph = NULL; + background = false; + mix_weight_offset = SVM_STACK_INVALID; + compile_failed = false; } int SVMCompiler::stack_size(SocketType::Type type) { - int size = 0; - - switch(type) { - case SocketType::FLOAT: - case SocketType::INT: - size = 1; - break; - case SocketType::COLOR: - case SocketType::VECTOR: - case SocketType::NORMAL: - case SocketType::POINT: - size = 3; - break; - case SocketType::CLOSURE: - size = 0; - break; - default: - assert(0); - break; - } - - return size; + int size = 0; + + switch (type) { + case SocketType::FLOAT: + case SocketType::INT: + size = 1; + break; + case SocketType::COLOR: + case SocketType::VECTOR: + case SocketType::NORMAL: + case SocketType::POINT: + size = 3; + break; + case SocketType::CLOSURE: + size = 0; + break; + default: + assert(0); + break; + } + + return size; } int SVMCompiler::stack_find_offset(int size) { - int offset = -1; + int offset = -1; - /* find free space in stack & mark as used */ - for(int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) { - if(active_stack.users[i]) num_unused = 0; - else num_unused++; + /* find free space in stack & mark as used */ + for (int i = 0, num_unused = 0; i < SVM_STACK_SIZE; i++) { + if (active_stack.users[i]) + num_unused = 0; + else + num_unused++; - if(num_unused == size) { - offset = i+1 - size; - max_stack_use = max(i+1, max_stack_use); + if (num_unused == size) { + offset = i + 1 - size; + max_stack_use = max(i + 1, max_stack_use); - while(i >= offset) - active_stack.users[i--] = 1; + while (i >= offset) + active_stack.users[i--] = 1; - return offset; - } - } + return offset; + } + } - if(!compile_failed) { - compile_failed = true; - fprintf(stderr, "Cycles: out of SVM stack space, shader \"%s\" too big.\n", current_shader->name.c_str()); - } + if (!compile_failed) { + compile_failed = true; + fprintf(stderr, + "Cycles: out of SVM stack space, shader \"%s\" too big.\n", + current_shader->name.c_str()); + } - return 0; + return 0; } int SVMCompiler::stack_find_offset(SocketType::Type type) { - return stack_find_offset(stack_size(type)); + return stack_find_offset(stack_size(type)); } void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset) { - int size = stack_size(type); + int size = stack_size(type); - for(int i = 0; i < size; i++) - active_stack.users[offset + i]--; + for (int i = 0; i < size; i++) + active_stack.users[offset + i]--; } int SVMCompiler::stack_assign(ShaderInput *input) { - /* stack offset assign? */ - if(input->stack_offset == SVM_STACK_INVALID) { - if(input->link) { - /* linked to output -> use output offset */ - assert(input->link->stack_offset != SVM_STACK_INVALID); - input->stack_offset = input->link->stack_offset; - } - else { - Node *node = input->parent; - - /* not linked to output -> add nodes to load default value */ - input->stack_offset = stack_find_offset(input->type()); - - if(input->type() == SocketType::FLOAT) { - add_node(NODE_VALUE_F, __float_as_int(node->get_float(input->socket_type)), input->stack_offset); - } - else if(input->type() == SocketType::INT) { - add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset); - } - else if(input->type() == SocketType::VECTOR || - input->type() == SocketType::NORMAL || - input->type() == SocketType::POINT || - input->type() == SocketType::COLOR) - { - - add_node(NODE_VALUE_V, input->stack_offset); - add_node(NODE_VALUE_V, node->get_float3(input->socket_type)); - } - else /* should not get called for closure */ - assert(0); - } - } - - return input->stack_offset; + /* stack offset assign? */ + if (input->stack_offset == SVM_STACK_INVALID) { + if (input->link) { + /* linked to output -> use output offset */ + assert(input->link->stack_offset != SVM_STACK_INVALID); + input->stack_offset = input->link->stack_offset; + } + else { + Node *node = input->parent; + + /* not linked to output -> add nodes to load default value */ + input->stack_offset = stack_find_offset(input->type()); + + if (input->type() == SocketType::FLOAT) { + add_node(NODE_VALUE_F, + __float_as_int(node->get_float(input->socket_type)), + input->stack_offset); + } + else if (input->type() == SocketType::INT) { + add_node(NODE_VALUE_F, node->get_int(input->socket_type), input->stack_offset); + } + else if (input->type() == SocketType::VECTOR || input->type() == SocketType::NORMAL || + input->type() == SocketType::POINT || input->type() == SocketType::COLOR) { + + add_node(NODE_VALUE_V, input->stack_offset); + add_node(NODE_VALUE_V, node->get_float3(input->socket_type)); + } + else /* should not get called for closure */ + assert(0); + } + } + + return input->stack_offset; } int SVMCompiler::stack_assign(ShaderOutput *output) { - /* if no stack offset assigned yet, find one */ - if(output->stack_offset == SVM_STACK_INVALID) - output->stack_offset = stack_find_offset(output->type()); + /* if no stack offset assigned yet, find one */ + if (output->stack_offset == SVM_STACK_INVALID) + output->stack_offset = stack_find_offset(output->type()); - return output->stack_offset; + return output->stack_offset; } int SVMCompiler::stack_assign_if_linked(ShaderInput *input) { - if(input->link) - return stack_assign(input); + if (input->link) + return stack_assign(input); - return SVM_STACK_INVALID; + return SVM_STACK_INVALID; } int SVMCompiler::stack_assign_if_linked(ShaderOutput *output) { - if(!output->links.empty()) - return stack_assign(output); + if (!output->links.empty()) + return stack_assign(output); - return SVM_STACK_INVALID; + return SVM_STACK_INVALID; } void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output) { - if(output->stack_offset == SVM_STACK_INVALID) { - assert(input->link); - assert(stack_size(output->type()) == stack_size(input->link->type())); + if (output->stack_offset == SVM_STACK_INVALID) { + assert(input->link); + assert(stack_size(output->type()) == stack_size(input->link->type())); - output->stack_offset = input->link->stack_offset; + output->stack_offset = input->link->stack_offset; - int size = stack_size(output->type()); + int size = stack_size(output->type()); - for(int i = 0; i < size; i++) - active_stack.users[output->stack_offset + i]++; - } + for (int i = 0; i < size; i++) + active_stack.users[output->stack_offset + i]++; + } } -void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done) +void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet &done) { - /* optimization we should add: - * find and lower user counts for outputs for which all inputs are done. - * this is done before the node is compiled, under the assumption that the - * node will first load all inputs from the stack and then writes its - * outputs. this used to work, but was disabled because it gave trouble - * with inputs getting stack positions assigned */ + /* optimization we should add: + * find and lower user counts for outputs for which all inputs are done. + * this is done before the node is compiled, under the assumption that the + * node will first load all inputs from the stack and then writes its + * outputs. this used to work, but was disabled because it gave trouble + * with inputs getting stack positions assigned */ - foreach(ShaderInput *input, node->inputs) { - ShaderOutput *output = input->link; + foreach (ShaderInput *input, node->inputs) { + ShaderOutput *output = input->link; - if(output && output->stack_offset != SVM_STACK_INVALID) { - bool all_done = true; + if (output && output->stack_offset != SVM_STACK_INVALID) { + bool all_done = true; - /* optimization we should add: verify if in->parent is actually used */ - foreach(ShaderInput *in, output->links) - if(in->parent != node && done.find(in->parent) == done.end()) - all_done = false; + /* optimization we should add: verify if in->parent is actually used */ + foreach (ShaderInput *in, output->links) + if (in->parent != node && done.find(in->parent) == done.end()) + all_done = false; - if(all_done) { - stack_clear_offset(output->type(), output->stack_offset); - output->stack_offset = SVM_STACK_INVALID; + if (all_done) { + stack_clear_offset(output->type(), output->stack_offset); + output->stack_offset = SVM_STACK_INVALID; - foreach(ShaderInput *in, output->links) - in->stack_offset = SVM_STACK_INVALID; - } - } - } + foreach (ShaderInput *in, output->links) + in->stack_offset = SVM_STACK_INVALID; + } + } + } } void SVMCompiler::stack_clear_temporary(ShaderNode *node) { - foreach(ShaderInput *input, node->inputs) { - if(!input->link && input->stack_offset != SVM_STACK_INVALID) { - stack_clear_offset(input->type(), input->stack_offset); - input->stack_offset = SVM_STACK_INVALID; - } - } + foreach (ShaderInput *input, node->inputs) { + if (!input->link && input->stack_offset != SVM_STACK_INVALID) { + stack_clear_offset(input->type(), input->stack_offset); + input->stack_offset = SVM_STACK_INVALID; + } + } } uint SVMCompiler::encode_uchar4(uint x, uint y, uint z, uint w) { - assert(x <= 255); - assert(y <= 255); - assert(z <= 255); - assert(w <= 255); + assert(x <= 255); + assert(y <= 255); + assert(z <= 255); + assert(w <= 255); - return (x) | (y << 8) | (z << 16) | (w << 24); + return (x) | (y << 8) | (z << 16) | (w << 24); } void SVMCompiler::add_node(int a, int b, int c, int d) { - current_svm_nodes.push_back_slow(make_int4(a, b, c, d)); + current_svm_nodes.push_back_slow(make_int4(a, b, c, d)); } void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c) { - current_svm_nodes.push_back_slow(make_int4(type, a, b, c)); + current_svm_nodes.push_back_slow(make_int4(type, a, b, c)); } -void SVMCompiler::add_node(ShaderNodeType type, const float3& f) +void SVMCompiler::add_node(ShaderNodeType type, const float3 &f) { - current_svm_nodes.push_back_slow(make_int4(type, - __float_as_int(f.x), - __float_as_int(f.y), - __float_as_int(f.z))); + current_svm_nodes.push_back_slow( + make_int4(type, __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z))); } -void SVMCompiler::add_node(const float4& f) +void SVMCompiler::add_node(const float4 &f) { - current_svm_nodes.push_back_slow(make_int4( - __float_as_int(f.x), - __float_as_int(f.y), - __float_as_int(f.z), - __float_as_int(f.w))); + current_svm_nodes.push_back_slow(make_int4( + __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w))); } uint SVMCompiler::attribute(ustring name) { - return shader_manager->get_attribute_id(name); + return shader_manager->get_attribute_id(name); } uint SVMCompiler::attribute(AttributeStandard std) { - return shader_manager->get_attribute_id(std); + return shader_manager->get_attribute_id(std); } uint SVMCompiler::attribute_standard(ustring name) { - AttributeStandard std = Attribute::name_standard(name.c_str()); - return (std)? attribute(std): attribute(name); + AttributeStandard std = Attribute::name_standard(name.c_str()); + return (std) ? attribute(std) : attribute(name); } -void SVMCompiler::find_dependencies(ShaderNodeSet& dependencies, - const ShaderNodeSet& done, +void SVMCompiler::find_dependencies(ShaderNodeSet &dependencies, + const ShaderNodeSet &done, ShaderInput *input, ShaderNode *skip_node) { - ShaderNode *node = (input->link)? input->link->parent: NULL; - if(node != NULL && - done.find(node) == done.end() && - node != skip_node && - dependencies.find(node) == dependencies.end()) - { - foreach(ShaderInput *in, node->inputs) { - find_dependencies(dependencies, done, in, skip_node); - } - dependencies.insert(node); - } -} - -void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done) -{ - node->compile(*this); - stack_clear_users(node, done); - stack_clear_temporary(node); - - if(current_type == SHADER_TYPE_SURFACE) { - if(node->has_spatial_varying()) - current_shader->has_surface_spatial_varying = true; - } - else if(current_type == SHADER_TYPE_VOLUME) { - if(node->has_spatial_varying()) - current_shader->has_volume_spatial_varying = true; - } - - if(node->has_object_dependency()) { - current_shader->has_object_dependency = true; - } - - if(node->has_attribute_dependency()) { - current_shader->has_attribute_dependency = true; - } - - if(node->has_integrator_dependency()) { - current_shader->has_integrator_dependency = true; - } -} - -void SVMCompiler::generate_svm_nodes(const ShaderNodeSet& nodes, - CompilerState *state) -{ - ShaderNodeSet& done = state->nodes_done; - vector<bool>& done_flag = state->nodes_done_flag; - - bool nodes_done; - do { - nodes_done = true; - - foreach(ShaderNode *node, nodes) { - if(!done_flag[node->id]) { - bool inputs_done = true; - - foreach(ShaderInput *input, node->inputs) { - if(input->link && !done_flag[input->link->parent->id]) { - inputs_done = false; - } - } - if(inputs_done) { - generate_node(node, done); - done.insert(node); - done_flag[node->id] = true; - } - else { - nodes_done = false; - } - } - } - } while(!nodes_done); -} - -void SVMCompiler::generate_closure_node(ShaderNode *node, - CompilerState *state) -{ - /* execute dependencies for closure */ - foreach(ShaderInput *in, node->inputs) { - if(in->link != NULL) { - ShaderNodeSet dependencies; - find_dependencies(dependencies, state->nodes_done, in); - generate_svm_nodes(dependencies, state); - } - } - - /* closure mix weight */ - const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; - ShaderInput *weight_in = node->input(weight_name); - - if(weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f)) - mix_weight_offset = stack_assign(weight_in); - else - mix_weight_offset = SVM_STACK_INVALID; - - /* compile closure itself */ - generate_node(node, state->nodes_done); - - mix_weight_offset = SVM_STACK_INVALID; - - if(current_type == SHADER_TYPE_SURFACE) { - if(node->has_surface_emission()) - current_shader->has_surface_emission = true; - if(node->has_surface_transparent()) - current_shader->has_surface_transparent = true; - if(node->has_surface_bssrdf()) { - current_shader->has_surface_bssrdf = true; - if(node->has_bssrdf_bump()) - current_shader->has_bssrdf_bump = true; - } - if(node->has_bump()) { - current_shader->has_bump = true; - } - } + ShaderNode *node = (input->link) ? input->link->parent : NULL; + if (node != NULL && done.find(node) == done.end() && node != skip_node && + dependencies.find(node) == dependencies.end()) { + foreach (ShaderInput *in, node->inputs) { + find_dependencies(dependencies, done, in, skip_node); + } + dependencies.insert(node); + } +} + +void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet &done) +{ + node->compile(*this); + stack_clear_users(node, done); + stack_clear_temporary(node); + + if (current_type == SHADER_TYPE_SURFACE) { + if (node->has_spatial_varying()) + current_shader->has_surface_spatial_varying = true; + } + else if (current_type == SHADER_TYPE_VOLUME) { + if (node->has_spatial_varying()) + current_shader->has_volume_spatial_varying = true; + } + + if (node->has_object_dependency()) { + current_shader->has_object_dependency = true; + } + + if (node->has_attribute_dependency()) { + current_shader->has_attribute_dependency = true; + } + + if (node->has_integrator_dependency()) { + current_shader->has_integrator_dependency = true; + } +} + +void SVMCompiler::generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state) +{ + ShaderNodeSet &done = state->nodes_done; + vector<bool> &done_flag = state->nodes_done_flag; + + bool nodes_done; + do { + nodes_done = true; + + foreach (ShaderNode *node, nodes) { + if (!done_flag[node->id]) { + bool inputs_done = true; + + foreach (ShaderInput *input, node->inputs) { + if (input->link && !done_flag[input->link->parent->id]) { + inputs_done = false; + } + } + if (inputs_done) { + generate_node(node, done); + done.insert(node); + done_flag[node->id] = true; + } + else { + nodes_done = false; + } + } + } + } while (!nodes_done); +} + +void SVMCompiler::generate_closure_node(ShaderNode *node, CompilerState *state) +{ + /* execute dependencies for closure */ + foreach (ShaderInput *in, node->inputs) { + if (in->link != NULL) { + ShaderNodeSet dependencies; + find_dependencies(dependencies, state->nodes_done, in); + generate_svm_nodes(dependencies, state); + } + } + + /* closure mix weight */ + const char *weight_name = (current_type == SHADER_TYPE_VOLUME) ? "VolumeMixWeight" : + "SurfaceMixWeight"; + ShaderInput *weight_in = node->input(weight_name); + + if (weight_in && (weight_in->link || node->get_float(weight_in->socket_type) != 1.0f)) + mix_weight_offset = stack_assign(weight_in); + else + mix_weight_offset = SVM_STACK_INVALID; + + /* compile closure itself */ + generate_node(node, state->nodes_done); + + mix_weight_offset = SVM_STACK_INVALID; + + if (current_type == SHADER_TYPE_SURFACE) { + if (node->has_surface_emission()) + current_shader->has_surface_emission = true; + if (node->has_surface_transparent()) + current_shader->has_surface_transparent = true; + if (node->has_surface_bssrdf()) { + current_shader->has_surface_bssrdf = true; + if (node->has_bssrdf_bump()) + current_shader->has_bssrdf_bump = true; + } + if (node->has_bump()) { + current_shader->has_bump = true; + } + } } void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, ShaderNode *node, CompilerState *state, - const ShaderNodeSet& shared) -{ - if(shared.find(node) != shared.end()) { - generate_multi_closure(root_node, node, state); - } - else { - foreach(ShaderInput *in, node->inputs) { - if(in->type() == SocketType::CLOSURE && in->link) - generated_shared_closure_nodes(root_node, - in->link->parent, - state, - shared); - } - } + const ShaderNodeSet &shared) +{ + if (shared.find(node) != shared.end()) { + generate_multi_closure(root_node, node, state); + } + else { + foreach (ShaderInput *in, node->inputs) { + if (in->type() == SocketType::CLOSURE && in->link) + generated_shared_closure_nodes(root_node, in->link->parent, state, shared); + } + } } void SVMCompiler::generate_multi_closure(ShaderNode *root_node, ShaderNode *node, CompilerState *state) { - /* only generate once */ - if(state->closure_done.find(node) != state->closure_done.end()) - return; - - state->closure_done.insert(node); - - if(node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) { - /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ - ShaderInput *cl1in = node->input("Closure1"); - ShaderInput *cl2in = node->input("Closure2"); - ShaderInput *facin = node->input("Fac"); - - /* skip empty mix/add closure nodes */ - if(!cl1in->link && !cl2in->link) - return; - - if(facin && facin->link) { - /* mix closure: generate instructions to compute mix weight */ - ShaderNodeSet dependencies; - find_dependencies(dependencies, state->nodes_done, facin); - generate_svm_nodes(dependencies, state); - - /* execute shared dependencies. this is needed to allow skipping - * of zero weight closures and their dependencies later, so we - * ensure that they only skip dependencies that are unique to them */ - ShaderNodeSet cl1deps, cl2deps, shareddeps; - - find_dependencies(cl1deps, state->nodes_done, cl1in); - find_dependencies(cl2deps, state->nodes_done, cl2in); - - ShaderNodeIDComparator node_id_comp; - set_intersection(cl1deps.begin(), cl1deps.end(), - cl2deps.begin(), cl2deps.end(), - std::inserter(shareddeps, shareddeps.begin()), - node_id_comp); - - /* it's possible some nodes are not shared between this mix node - * inputs, but still needed to be always executed, this mainly - * happens when a node of current subbranch is used by a parent - * node or so */ - if(root_node != node) { - foreach(ShaderInput *in, root_node->inputs) { - ShaderNodeSet rootdeps; - find_dependencies(rootdeps, state->nodes_done, in, node); - set_intersection(rootdeps.begin(), rootdeps.end(), - cl1deps.begin(), cl1deps.end(), - std::inserter(shareddeps, shareddeps.begin()), - node_id_comp); - set_intersection(rootdeps.begin(), rootdeps.end(), - cl2deps.begin(), cl2deps.end(), - std::inserter(shareddeps, shareddeps.begin()), - node_id_comp); - } - } - - if(!shareddeps.empty()) { - if(cl1in->link) { - generated_shared_closure_nodes(root_node, - cl1in->link->parent, - state, - shareddeps); - } - if(cl2in->link) { - generated_shared_closure_nodes(root_node, - cl2in->link->parent, - state, - shareddeps); - } - - generate_svm_nodes(shareddeps, state); - } - - /* generate instructions for input closure 1 */ - if(cl1in->link) { - /* Add instruction to skip closure and its dependencies if mix - * weight is zero. - */ - current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, - 0, - stack_assign(facin), - 0)); - int node_jump_skip_index = current_svm_nodes.size() - 1; - - generate_multi_closure(root_node, cl1in->link->parent, state); - - /* Fill in jump instruction location to be after closure. */ - current_svm_nodes[node_jump_skip_index].y = - current_svm_nodes.size() - node_jump_skip_index - 1; - } - - /* generate instructions for input closure 2 */ - if(cl2in->link) { - /* Add instruction to skip closure and its dependencies if mix - * weight is zero. - */ - current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, - 0, - stack_assign(facin), - 0)); - int node_jump_skip_index = current_svm_nodes.size() - 1; - - generate_multi_closure(root_node, cl2in->link->parent, state); - - /* Fill in jump instruction location to be after closure. */ - current_svm_nodes[node_jump_skip_index].y = - current_svm_nodes.size() - node_jump_skip_index - 1; - } - - /* unassign */ - facin->stack_offset = SVM_STACK_INVALID; - } - else { - /* execute closures and their dependencies, no runtime checks - * to skip closures here because was already optimized due to - * fixed weight or add closure that always needs both */ - if(cl1in->link) - generate_multi_closure(root_node, cl1in->link->parent, state); - if(cl2in->link) - generate_multi_closure(root_node, cl2in->link->parent, state); - } - } - else { - generate_closure_node(node, state); - } - - state->nodes_done.insert(node); - state->nodes_done_flag[node->id] = true; + /* only generate once */ + if (state->closure_done.find(node) != state->closure_done.end()) + return; + + state->closure_done.insert(node); + + if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) { + /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ + ShaderInput *cl1in = node->input("Closure1"); + ShaderInput *cl2in = node->input("Closure2"); + ShaderInput *facin = node->input("Fac"); + + /* skip empty mix/add closure nodes */ + if (!cl1in->link && !cl2in->link) + return; + + if (facin && facin->link) { + /* mix closure: generate instructions to compute mix weight */ + ShaderNodeSet dependencies; + find_dependencies(dependencies, state->nodes_done, facin); + generate_svm_nodes(dependencies, state); + + /* execute shared dependencies. this is needed to allow skipping + * of zero weight closures and their dependencies later, so we + * ensure that they only skip dependencies that are unique to them */ + ShaderNodeSet cl1deps, cl2deps, shareddeps; + + find_dependencies(cl1deps, state->nodes_done, cl1in); + find_dependencies(cl2deps, state->nodes_done, cl2in); + + ShaderNodeIDComparator node_id_comp; + set_intersection(cl1deps.begin(), + cl1deps.end(), + cl2deps.begin(), + cl2deps.end(), + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); + + /* it's possible some nodes are not shared between this mix node + * inputs, but still needed to be always executed, this mainly + * happens when a node of current subbranch is used by a parent + * node or so */ + if (root_node != node) { + foreach (ShaderInput *in, root_node->inputs) { + ShaderNodeSet rootdeps; + find_dependencies(rootdeps, state->nodes_done, in, node); + set_intersection(rootdeps.begin(), + rootdeps.end(), + cl1deps.begin(), + cl1deps.end(), + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); + set_intersection(rootdeps.begin(), + rootdeps.end(), + cl2deps.begin(), + cl2deps.end(), + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); + } + } + + if (!shareddeps.empty()) { + if (cl1in->link) { + generated_shared_closure_nodes(root_node, cl1in->link->parent, state, shareddeps); + } + if (cl2in->link) { + generated_shared_closure_nodes(root_node, cl2in->link->parent, state, shareddeps); + } + + generate_svm_nodes(shareddeps, state); + } + + /* generate instructions for input closure 1 */ + if (cl1in->link) { + /* Add instruction to skip closure and its dependencies if mix + * weight is zero. + */ + current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0)); + int node_jump_skip_index = current_svm_nodes.size() - 1; + + generate_multi_closure(root_node, cl1in->link->parent, state); + + /* Fill in jump instruction location to be after closure. */ + current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() - + node_jump_skip_index - 1; + } + + /* generate instructions for input closure 2 */ + if (cl2in->link) { + /* Add instruction to skip closure and its dependencies if mix + * weight is zero. + */ + current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0)); + int node_jump_skip_index = current_svm_nodes.size() - 1; + + generate_multi_closure(root_node, cl2in->link->parent, state); + + /* Fill in jump instruction location to be after closure. */ + current_svm_nodes[node_jump_skip_index].y = current_svm_nodes.size() - + node_jump_skip_index - 1; + } + + /* unassign */ + facin->stack_offset = SVM_STACK_INVALID; + } + else { + /* execute closures and their dependencies, no runtime checks + * to skip closures here because was already optimized due to + * fixed weight or add closure that always needs both */ + if (cl1in->link) + generate_multi_closure(root_node, cl1in->link->parent, state); + if (cl2in->link) + generate_multi_closure(root_node, cl2in->link->parent, state); + } + } + else { + generate_closure_node(node, state); + } + + state->nodes_done.insert(node); + state->nodes_done_flag[node->id] = true; } - void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type) { - /* Converting a shader graph into svm_nodes that can be executed - * sequentially on the virtual machine is fairly simple. We can keep - * looping over nodes and each time all the inputs of a node are - * ready, we add svm_nodes for it that read the inputs from the - * stack and write outputs back to the stack. - * - * With the SVM, we always sample only a single closure. We can think - * of all closures nodes as a binary tree with mix closures as inner - * nodes and other closures as leafs. The SVM will traverse that tree, - * each time deciding to go left or right depending on the mix weights, - * until a closure is found. - * - * We only execute nodes that are needed for the mix weights and chosen - * closure. - */ - - current_type = type; - current_graph = graph; - - /* get input in output node */ - ShaderNode *node = graph->output(); - ShaderInput *clin = NULL; - - switch(type) { - case SHADER_TYPE_SURFACE: - clin = node->input("Surface"); - break; - case SHADER_TYPE_VOLUME: - clin = node->input("Volume"); - break; - case SHADER_TYPE_DISPLACEMENT: - clin = node->input("Displacement"); - break; - case SHADER_TYPE_BUMP: - clin = node->input("Normal"); - break; - default: - assert(0); - break; - } - - /* clear all compiler state */ - memset((void *)&active_stack, 0, sizeof(active_stack)); - current_svm_nodes.clear(); - - foreach(ShaderNode *node_iter, graph->nodes) { - foreach(ShaderInput *input, node_iter->inputs) - input->stack_offset = SVM_STACK_INVALID; - foreach(ShaderOutput *output, node_iter->outputs) - output->stack_offset = SVM_STACK_INVALID; - } - - /* for the bump shader we need add a node to store the shader state */ - bool need_bump_state = (type == SHADER_TYPE_BUMP) && (shader->displacement_method == DISPLACE_BOTH); - int bump_state_offset = SVM_STACK_INVALID; - if(need_bump_state) { - bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE); - add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset); - } - - if(shader->used) { - if(clin->link) { - bool generate = false; - - switch(type) { - case SHADER_TYPE_SURFACE: /* generate surface shader */ - generate = true; - shader->has_surface = true; - break; - case SHADER_TYPE_VOLUME: /* generate volume shader */ - generate = true; - shader->has_volume = true; - break; - case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */ - generate = true; - shader->has_displacement = true; - break; - case SHADER_TYPE_BUMP: /* generate bump shader */ - generate = true; - break; - default: - break; - } - - if(generate) { - CompilerState state(graph); - generate_multi_closure(clin->link->parent, - clin->link->parent, - &state); - } - } - - /* compile output node */ - node->compile(*this); - } - - /* add node to restore state after bump shader has finished */ - if(need_bump_state) { - add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset); - } - - /* if compile failed, generate empty shader */ - if(compile_failed) { - current_svm_nodes.clear(); - compile_failed = false; - } - - /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */ - if(type != SHADER_TYPE_BUMP) { - add_node(NODE_END, 0, 0, 0); - } -} - -void SVMCompiler::compile(Scene *scene, - Shader *shader, - array<int4>& svm_nodes, - int index, - Summary *summary) -{ - /* copy graph for shader with bump mapping */ - ShaderNode *output = shader->graph->output(); - int start_num_svm_nodes = svm_nodes.size(); - - const double time_start = time_dt(); - - bool has_bump = (shader->displacement_method != DISPLACE_TRUE) && - output->input("Surface")->link && output->input("Displacement")->link; - - /* finalize */ - { - scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL); - shader->graph->finalize(scene, - has_bump, - shader->has_integrator_dependency, - shader->displacement_method == DISPLACE_BOTH); - } - - current_shader = shader; - - shader->has_surface = false; - shader->has_surface_emission = false; - shader->has_surface_transparent = false; - shader->has_surface_bssrdf = false; - shader->has_bump = has_bump; - shader->has_bssrdf_bump = has_bump; - shader->has_volume = false; - shader->has_displacement = false; - shader->has_surface_spatial_varying = false; - shader->has_volume_spatial_varying = false; - shader->has_object_dependency = false; - shader->has_attribute_dependency = false; - shader->has_integrator_dependency = false; - - /* generate bump shader */ - if(has_bump) { - scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL); - compile_type(shader, shader->graph, SHADER_TYPE_BUMP); - svm_nodes[index].y = svm_nodes.size(); - svm_nodes.append(current_svm_nodes); - } - - /* generate surface shader */ - { - scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL); - compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); - /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */ - if(!has_bump) { - svm_nodes[index].y = svm_nodes.size(); - } - svm_nodes.append(current_svm_nodes); - } - - /* generate volume shader */ - { - scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL); - compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); - svm_nodes[index].z = svm_nodes.size(); - svm_nodes.append(current_svm_nodes); - } - - /* generate displacement shader */ - { - scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL); - compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); - svm_nodes[index].w = svm_nodes.size(); - svm_nodes.append(current_svm_nodes); - } - - /* Fill in summary information. */ - if(summary != NULL) { - summary->time_total = time_dt() - time_start; - summary->peak_stack_usage = max_stack_use; - summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes; - } + /* Converting a shader graph into svm_nodes that can be executed + * sequentially on the virtual machine is fairly simple. We can keep + * looping over nodes and each time all the inputs of a node are + * ready, we add svm_nodes for it that read the inputs from the + * stack and write outputs back to the stack. + * + * With the SVM, we always sample only a single closure. We can think + * of all closures nodes as a binary tree with mix closures as inner + * nodes and other closures as leafs. The SVM will traverse that tree, + * each time deciding to go left or right depending on the mix weights, + * until a closure is found. + * + * We only execute nodes that are needed for the mix weights and chosen + * closure. + */ + + current_type = type; + current_graph = graph; + + /* get input in output node */ + ShaderNode *node = graph->output(); + ShaderInput *clin = NULL; + + switch (type) { + case SHADER_TYPE_SURFACE: + clin = node->input("Surface"); + break; + case SHADER_TYPE_VOLUME: + clin = node->input("Volume"); + break; + case SHADER_TYPE_DISPLACEMENT: + clin = node->input("Displacement"); + break; + case SHADER_TYPE_BUMP: + clin = node->input("Normal"); + break; + default: + assert(0); + break; + } + + /* clear all compiler state */ + memset((void *)&active_stack, 0, sizeof(active_stack)); + current_svm_nodes.clear(); + + foreach (ShaderNode *node_iter, graph->nodes) { + foreach (ShaderInput *input, node_iter->inputs) + input->stack_offset = SVM_STACK_INVALID; + foreach (ShaderOutput *output, node_iter->outputs) + output->stack_offset = SVM_STACK_INVALID; + } + + /* for the bump shader we need add a node to store the shader state */ + bool need_bump_state = (type == SHADER_TYPE_BUMP) && + (shader->displacement_method == DISPLACE_BOTH); + int bump_state_offset = SVM_STACK_INVALID; + if (need_bump_state) { + bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE); + add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset); + } + + if (shader->used) { + if (clin->link) { + bool generate = false; + + switch (type) { + case SHADER_TYPE_SURFACE: /* generate surface shader */ + generate = true; + shader->has_surface = true; + break; + case SHADER_TYPE_VOLUME: /* generate volume shader */ + generate = true; + shader->has_volume = true; + break; + case SHADER_TYPE_DISPLACEMENT: /* generate displacement shader */ + generate = true; + shader->has_displacement = true; + break; + case SHADER_TYPE_BUMP: /* generate bump shader */ + generate = true; + break; + default: + break; + } + + if (generate) { + CompilerState state(graph); + generate_multi_closure(clin->link->parent, clin->link->parent, &state); + } + } + + /* compile output node */ + node->compile(*this); + } + + /* add node to restore state after bump shader has finished */ + if (need_bump_state) { + add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset); + } + + /* if compile failed, generate empty shader */ + if (compile_failed) { + current_svm_nodes.clear(); + compile_failed = false; + } + + /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */ + if (type != SHADER_TYPE_BUMP) { + add_node(NODE_END, 0, 0, 0); + } +} + +void SVMCompiler::compile( + Scene *scene, Shader *shader, array<int4> &svm_nodes, int index, Summary *summary) +{ + /* copy graph for shader with bump mapping */ + ShaderNode *output = shader->graph->output(); + int start_num_svm_nodes = svm_nodes.size(); + + const double time_start = time_dt(); + + bool has_bump = (shader->displacement_method != DISPLACE_TRUE) && + output->input("Surface")->link && output->input("Displacement")->link; + + /* finalize */ + { + scoped_timer timer((summary != NULL) ? &summary->time_finalize : NULL); + shader->graph->finalize(scene, + has_bump, + shader->has_integrator_dependency, + shader->displacement_method == DISPLACE_BOTH); + } + + current_shader = shader; + + shader->has_surface = false; + shader->has_surface_emission = false; + shader->has_surface_transparent = false; + shader->has_surface_bssrdf = false; + shader->has_bump = has_bump; + shader->has_bssrdf_bump = has_bump; + shader->has_volume = false; + shader->has_displacement = false; + shader->has_surface_spatial_varying = false; + shader->has_volume_spatial_varying = false; + shader->has_object_dependency = false; + shader->has_attribute_dependency = false; + shader->has_integrator_dependency = false; + + /* generate bump shader */ + if (has_bump) { + scoped_timer timer((summary != NULL) ? &summary->time_generate_bump : NULL); + compile_type(shader, shader->graph, SHADER_TYPE_BUMP); + svm_nodes[index].y = svm_nodes.size(); + svm_nodes.append(current_svm_nodes); + } + + /* generate surface shader */ + { + scoped_timer timer((summary != NULL) ? &summary->time_generate_surface : NULL); + compile_type(shader, shader->graph, SHADER_TYPE_SURFACE); + /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */ + if (!has_bump) { + svm_nodes[index].y = svm_nodes.size(); + } + svm_nodes.append(current_svm_nodes); + } + + /* generate volume shader */ + { + scoped_timer timer((summary != NULL) ? &summary->time_generate_volume : NULL); + compile_type(shader, shader->graph, SHADER_TYPE_VOLUME); + svm_nodes[index].z = svm_nodes.size(); + svm_nodes.append(current_svm_nodes); + } + + /* generate displacement shader */ + { + scoped_timer timer((summary != NULL) ? &summary->time_generate_displacement : NULL); + compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT); + svm_nodes[index].w = svm_nodes.size(); + svm_nodes.append(current_svm_nodes); + } + + /* Fill in summary information. */ + if (summary != NULL) { + summary->time_total = time_dt() - time_start; + summary->peak_stack_usage = max_stack_use; + summary->num_svm_nodes = svm_nodes.size() - start_num_svm_nodes; + } } /* Compiler summary implementation. */ SVMCompiler::Summary::Summary() - : num_svm_nodes(0), - peak_stack_usage(0), - time_finalize(0.0), - time_generate_surface(0.0), - time_generate_bump(0.0), - time_generate_volume(0.0), - time_generate_displacement(0.0), - time_total(0.0) + : num_svm_nodes(0), + peak_stack_usage(0), + time_finalize(0.0), + time_generate_surface(0.0), + time_generate_bump(0.0), + time_generate_volume(0.0), + time_generate_displacement(0.0), + time_total(0.0) { } string SVMCompiler::Summary::full_report() const { - string report = ""; - report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes); - report += string_printf("Peak stack usage: %d\n", peak_stack_usage); + string report = ""; + report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes); + report += string_printf("Peak stack usage: %d\n", peak_stack_usage); - report += string_printf("Time (in seconds):\n"); - report += string_printf("Finalize: %f\n", time_finalize); - report += string_printf(" Surface: %f\n", time_generate_surface); - report += string_printf(" Bump: %f\n", time_generate_bump); - report += string_printf(" Volume: %f\n", time_generate_volume); - report += string_printf(" Displacement: %f\n", time_generate_displacement); - report += string_printf("Generate: %f\n", time_generate_surface + - time_generate_bump + - time_generate_volume + - time_generate_displacement); - report += string_printf("Total: %f\n", time_total); + report += string_printf("Time (in seconds):\n"); + report += string_printf("Finalize: %f\n", time_finalize); + report += string_printf(" Surface: %f\n", time_generate_surface); + report += string_printf(" Bump: %f\n", time_generate_bump); + report += string_printf(" Volume: %f\n", time_generate_volume); + report += string_printf(" Displacement: %f\n", time_generate_displacement); + report += string_printf("Generate: %f\n", + time_generate_surface + time_generate_bump + time_generate_volume + + time_generate_displacement); + report += string_printf("Total: %f\n", time_total); - return report; + return report; } /* Global state of the compiler. */ SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph) { - int max_id = 0; - foreach(ShaderNode *node, graph->nodes) { - max_id = max(node->id, max_id); - } - nodes_done_flag.resize(max_id + 1, false); + int max_id = 0; + foreach (ShaderNode *node, graph->nodes) { + max_id = max(node->id, max_id); + } + nodes_done_flag.resize(max_id + 1, false); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index ddf35602fa6..d6964fb158b 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -40,186 +40,196 @@ class ShaderOutput; /* Shader Manager */ class SVMShaderManager : public ShaderManager { -public: - SVMShaderManager(); - ~SVMShaderManager(); + public: + SVMShaderManager(); + ~SVMShaderManager(); - void reset(Scene *scene); + void reset(Scene *scene); - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_free(Device *device, DeviceScene *dscene, Scene *scene); + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free(Device *device, DeviceScene *dscene, Scene *scene); -protected: - /* Lock used to synchronize threaded nodes compilation. */ - thread_spin_lock nodes_lock_; + protected: + /* Lock used to synchronize threaded nodes compilation. */ + thread_spin_lock nodes_lock_; - void device_update_shader(Scene *scene, - Shader *shader, - Progress *progress, - array<int4> *global_svm_nodes); + void device_update_shader(Scene *scene, + Shader *shader, + Progress *progress, + array<int4> *global_svm_nodes); }; /* Graph Compiler */ class SVMCompiler { -public: - struct Summary { - Summary(); - - /* Number of SVM nodes shader was compiled into. */ - int num_svm_nodes; - - /* Peak stack usage during shader evaluation. */ - int peak_stack_usage; - - /* Time spent on surface graph finalization. */ - double time_finalize; - - /* Time spent on generating SVM nodes for surface shader. */ - double time_generate_surface; - - /* Time spent on generating SVM nodes for bump shader. */ - double time_generate_bump; - - /* Time spent on generating SVM nodes for volume shader. */ - double time_generate_volume; - - /* Time spent on generating SVM nodes for displacement shader. */ - double time_generate_displacement; - - /* Total time spent on all routines. */ - double time_total; - - /* A full multiline description of the state of the compiler after - * compilation. - */ - string full_report() const; - }; - - SVMCompiler(ShaderManager *shader_manager, - ImageManager *image_manager, - LightManager *light_manager); - void compile(Scene *scene, - Shader *shader, - array<int4>& svm_nodes, - int index, - Summary *summary = NULL); - - int stack_assign(ShaderOutput *output); - int stack_assign(ShaderInput *input); - int stack_assign_if_linked(ShaderInput *input); - int stack_assign_if_linked(ShaderOutput *output); - int stack_find_offset(int size); - int stack_find_offset(SocketType::Type type); - void stack_clear_offset(SocketType::Type type, int offset); - void stack_link(ShaderInput *input, ShaderOutput *output); - - void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0); - void add_node(int a = 0, int b = 0, int c = 0, int d = 0); - void add_node(ShaderNodeType type, const float3& f); - void add_node(const float4& f); - uint attribute(ustring name); - uint attribute(AttributeStandard std); - uint attribute_standard(ustring name); - uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0); - uint closure_mix_weight_offset() { return mix_weight_offset; } - - ShaderType output_type() { return current_type; } - - ImageManager *image_manager; - ShaderManager *shader_manager; - LightManager *light_manager; - bool background; - -protected: - /* stack */ - struct Stack { - Stack() { memset(users, 0, sizeof(users)); } - Stack(const Stack& other) { memcpy(users, other.users, sizeof(users)); } - Stack& operator=(const Stack& other) { memcpy(users, other.users, sizeof(users)); return *this; } - - bool empty() - { - for(int i = 0; i < SVM_STACK_SIZE; i++) - if(users[i]) - return false; - - return true; - } - - void print() - { - printf("stack <"); - - for(int i = 0; i < SVM_STACK_SIZE; i++) - printf((users[i])? "*": " "); - - printf(">\n"); - } - - int users[SVM_STACK_SIZE]; - }; - - /* Global state of the compiler accessible from the compilation routines. */ - struct CompilerState { - explicit CompilerState(ShaderGraph *graph); - - /* ** Global state, used by various compilation steps. ** */ - - /* Set of nodes which were already compiled. */ - ShaderNodeSet nodes_done; - - /* Set of closures which were already compiled. */ - ShaderNodeSet closure_done; - - /* ** SVM nodes generation state ** */ - - /* Flag whether the node with corresponding ID was already compiled or - * not. Array element with index i corresponds to a node with such if. - * - * TODO(sergey): This is actually a copy of nodes_done just in another - * notation. We can de-duplicate this storage actually after switching - * all areas to use this flags array. - */ - vector<bool> nodes_done_flag; - }; - - void stack_clear_temporary(ShaderNode *node); - int stack_size(SocketType::Type type); - void stack_clear_users(ShaderNode *node, ShaderNodeSet& done); - - /* single closure */ - void find_dependencies(ShaderNodeSet& dependencies, - const ShaderNodeSet& done, - ShaderInput *input, - ShaderNode *skip_node = NULL); - void generate_node(ShaderNode *node, ShaderNodeSet& done); - void generate_closure_node(ShaderNode *node, CompilerState *state); - void generated_shared_closure_nodes(ShaderNode *root_node, - ShaderNode *node, - CompilerState *state, - const ShaderNodeSet& shared); - void generate_svm_nodes(const ShaderNodeSet& nodes, - CompilerState *state); - - /* multi closure */ - void generate_multi_closure(ShaderNode *root_node, - ShaderNode *node, - CompilerState *state); - - /* compile */ - void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); - - array<int4> current_svm_nodes; - ShaderType current_type; - Shader *current_shader; - ShaderGraph *current_graph; - Stack active_stack; - int max_stack_use; - uint mix_weight_offset; - bool compile_failed; + public: + struct Summary { + Summary(); + + /* Number of SVM nodes shader was compiled into. */ + int num_svm_nodes; + + /* Peak stack usage during shader evaluation. */ + int peak_stack_usage; + + /* Time spent on surface graph finalization. */ + double time_finalize; + + /* Time spent on generating SVM nodes for surface shader. */ + double time_generate_surface; + + /* Time spent on generating SVM nodes for bump shader. */ + double time_generate_bump; + + /* Time spent on generating SVM nodes for volume shader. */ + double time_generate_volume; + + /* Time spent on generating SVM nodes for displacement shader. */ + double time_generate_displacement; + + /* Total time spent on all routines. */ + double time_total; + + /* A full multiline description of the state of the compiler after + * compilation. + */ + string full_report() const; + }; + + SVMCompiler(ShaderManager *shader_manager, + ImageManager *image_manager, + LightManager *light_manager); + void compile( + Scene *scene, Shader *shader, array<int4> &svm_nodes, int index, Summary *summary = NULL); + + int stack_assign(ShaderOutput *output); + int stack_assign(ShaderInput *input); + int stack_assign_if_linked(ShaderInput *input); + int stack_assign_if_linked(ShaderOutput *output); + int stack_find_offset(int size); + int stack_find_offset(SocketType::Type type); + void stack_clear_offset(SocketType::Type type, int offset); + void stack_link(ShaderInput *input, ShaderOutput *output); + + void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0); + void add_node(int a = 0, int b = 0, int c = 0, int d = 0); + void add_node(ShaderNodeType type, const float3 &f); + void add_node(const float4 &f); + uint attribute(ustring name); + uint attribute(AttributeStandard std); + uint attribute_standard(ustring name); + uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0); + uint closure_mix_weight_offset() + { + return mix_weight_offset; + } + + ShaderType output_type() + { + return current_type; + } + + ImageManager *image_manager; + ShaderManager *shader_manager; + LightManager *light_manager; + bool background; + + protected: + /* stack */ + struct Stack { + Stack() + { + memset(users, 0, sizeof(users)); + } + Stack(const Stack &other) + { + memcpy(users, other.users, sizeof(users)); + } + Stack &operator=(const Stack &other) + { + memcpy(users, other.users, sizeof(users)); + return *this; + } + + bool empty() + { + for (int i = 0; i < SVM_STACK_SIZE; i++) + if (users[i]) + return false; + + return true; + } + + void print() + { + printf("stack <"); + + for (int i = 0; i < SVM_STACK_SIZE; i++) + printf((users[i]) ? "*" : " "); + + printf(">\n"); + } + + int users[SVM_STACK_SIZE]; + }; + + /* Global state of the compiler accessible from the compilation routines. */ + struct CompilerState { + explicit CompilerState(ShaderGraph *graph); + + /* ** Global state, used by various compilation steps. ** */ + + /* Set of nodes which were already compiled. */ + ShaderNodeSet nodes_done; + + /* Set of closures which were already compiled. */ + ShaderNodeSet closure_done; + + /* ** SVM nodes generation state ** */ + + /* Flag whether the node with corresponding ID was already compiled or + * not. Array element with index i corresponds to a node with such if. + * + * TODO(sergey): This is actually a copy of nodes_done just in another + * notation. We can de-duplicate this storage actually after switching + * all areas to use this flags array. + */ + vector<bool> nodes_done_flag; + }; + + void stack_clear_temporary(ShaderNode *node); + int stack_size(SocketType::Type type); + void stack_clear_users(ShaderNode *node, ShaderNodeSet &done); + + /* single closure */ + void find_dependencies(ShaderNodeSet &dependencies, + const ShaderNodeSet &done, + ShaderInput *input, + ShaderNode *skip_node = NULL); + void generate_node(ShaderNode *node, ShaderNodeSet &done); + void generate_closure_node(ShaderNode *node, CompilerState *state); + void generated_shared_closure_nodes(ShaderNode *root_node, + ShaderNode *node, + CompilerState *state, + const ShaderNodeSet &shared); + void generate_svm_nodes(const ShaderNodeSet &nodes, CompilerState *state); + + /* multi closure */ + void generate_multi_closure(ShaderNode *root_node, ShaderNode *node, CompilerState *state); + + /* compile */ + void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type); + + array<int4> current_svm_nodes; + ShaderType current_type; + Shader *current_shader; + ShaderGraph *current_graph; + Stack active_stack; + int max_stack_use; + uint mix_weight_offset; + bool compile_failed; }; CCL_NAMESPACE_END -#endif /* __SVM_H__ */ +#endif /* __SVM_H__ */ diff --git a/intern/cycles/render/tables.cpp b/intern/cycles/render/tables.cpp index ddbb138f059..d88925939e3 100644 --- a/intern/cycles/render/tables.cpp +++ b/intern/cycles/render/tables.cpp @@ -26,92 +26,92 @@ CCL_NAMESPACE_BEGIN LookupTables::LookupTables() { - need_update = true; + need_update = true; } LookupTables::~LookupTables() { - assert(lookup_tables.size() == 0); + assert(lookup_tables.size() == 0); } void LookupTables::device_update(Device *, DeviceScene *dscene) { - if(!need_update) - return; + if (!need_update) + return; - VLOG(1) << "Total " << lookup_tables.size() << " lookup tables."; + VLOG(1) << "Total " << lookup_tables.size() << " lookup tables."; - if(lookup_tables.size() > 0) - dscene->lookup_table.copy_to_device(); + if (lookup_tables.size() > 0) + dscene->lookup_table.copy_to_device(); - need_update = false; + need_update = false; } void LookupTables::device_free(Device *, DeviceScene *dscene) { - dscene->lookup_table.free(); + dscene->lookup_table.free(); } static size_t round_up_to_multiple(size_t size, size_t chunk) { - return ((size + chunk - 1)/chunk) * chunk; + return ((size + chunk - 1) / chunk) * chunk; } -size_t LookupTables::add_table(DeviceScene *dscene, vector<float>& data) +size_t LookupTables::add_table(DeviceScene *dscene, vector<float> &data) { - assert(data.size() > 0); + assert(data.size() > 0); - need_update = true; + need_update = true; - Table new_table; - new_table.offset = 0; - new_table.size = round_up_to_multiple(data.size(), TABLE_CHUNK_SIZE); + 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; + /* 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; - } + 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); - } + 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 */ - float *dtable = dscene->lookup_table.data(); - memcpy(dtable + new_table.offset, &data[0], sizeof(float) * data.size()); + /* copy table data and return offset */ + float *dtable = dscene->lookup_table.data(); + memcpy(dtable + new_table.offset, &data[0], sizeof(float) * data.size()); - return new_table.offset; + return new_table.offset; } void LookupTables::remove_table(size_t *offset) { - if(*offset == TABLE_OFFSET_INVALID) { - /* The table isn't even allocated, so just return here. */ - return; - } + if (*offset == TABLE_OFFSET_INVALID) { + /* The table isn't even allocated, so just return here. */ + return; + } - need_update = true; + need_update = true; - list<Table>::iterator table; + list<Table>::iterator table; - for(table = lookup_tables.begin(); table != lookup_tables.end(); table++) { - if(table->offset == *offset) { - lookup_tables.erase(table); - *offset = TABLE_OFFSET_INVALID; - return; - } - } + for (table = lookup_tables.begin(); table != lookup_tables.end(); table++) { + if (table->offset == *offset) { + lookup_tables.erase(table); + *offset = TABLE_OFFSET_INVALID; + return; + } + } - assert(table != lookup_tables.end()); + assert(table != lookup_tables.end()); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/tables.h b/intern/cycles/render/tables.h index 709333cb1b6..12b59bb0aeb 100644 --- a/intern/cycles/render/tables.h +++ b/intern/cycles/render/tables.h @@ -29,25 +29,25 @@ enum { TABLE_CHUNK_SIZE = 256 }; enum { TABLE_OFFSET_INVALID = -1 }; class LookupTables { -public: - struct Table { - size_t offset; - size_t size; - }; + public: + struct Table { + size_t offset; + size_t size; + }; - bool need_update; - list<Table> lookup_tables; + bool need_update; + list<Table> lookup_tables; - LookupTables(); - ~LookupTables(); + LookupTables(); + ~LookupTables(); - void device_update(Device *device, DeviceScene *dscene); - void device_free(Device *device, DeviceScene *dscene); + void device_update(Device *device, DeviceScene *dscene); + void device_free(Device *device, DeviceScene *dscene); - size_t add_table(DeviceScene *dscene, vector<float>& data); - void remove_table(size_t *offset); + size_t add_table(DeviceScene *dscene, vector<float> &data); + void remove_table(size_t *offset); }; CCL_NAMESPACE_END -#endif /* __TABLES_H__ */ +#endif /* __TABLES_H__ */ diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index dc863b067b0..3148b5ef664 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -25,89 +25,93 @@ CCL_NAMESPACE_BEGIN namespace { class TileComparator { -public: - TileComparator(TileOrder order_, int2 center_, Tile *tiles_) - : order(order_), - center(center_), - tiles(tiles_) - {} - - bool operator()(int a, int b) - { - switch(order) { - case TILE_CENTER: - { - float2 dist_a = make_float2(center.x - (tiles[a].x + tiles[a].w/2), - center.y - (tiles[a].y + tiles[a].h/2)); - float2 dist_b = make_float2(center.x - (tiles[b].x + tiles[b].w/2), - center.y - (tiles[b].y + tiles[b].h/2)); - return dot(dist_a, dist_a) < dot(dist_b, dist_b); - } - case TILE_LEFT_TO_RIGHT: - return (tiles[a].x == tiles[b].x)? (tiles[a].y < tiles[b].y): (tiles[a].x < tiles[b].x); - case TILE_RIGHT_TO_LEFT: - return (tiles[a].x == tiles[b].x)? (tiles[a].y < tiles[b].y): (tiles[a].x > tiles[b].x); - case TILE_TOP_TO_BOTTOM: - return (tiles[a].y == tiles[b].y)? (tiles[a].x < tiles[b].x): (tiles[a].y > tiles[b].y); - case TILE_BOTTOM_TO_TOP: - default: - return (tiles[a].y == tiles[b].y)? (tiles[a].x < tiles[b].x): (tiles[a].y < tiles[b].y); - } - } - -protected: - TileOrder order; - int2 center; - Tile *tiles; + public: + TileComparator(TileOrder order_, int2 center_, Tile *tiles_) + : order(order_), center(center_), tiles(tiles_) + { + } + + bool operator()(int a, int b) + { + switch (order) { + case TILE_CENTER: { + float2 dist_a = make_float2(center.x - (tiles[a].x + tiles[a].w / 2), + center.y - (tiles[a].y + tiles[a].h / 2)); + float2 dist_b = make_float2(center.x - (tiles[b].x + tiles[b].w / 2), + center.y - (tiles[b].y + tiles[b].h / 2)); + return dot(dist_a, dist_a) < dot(dist_b, dist_b); + } + case TILE_LEFT_TO_RIGHT: + return (tiles[a].x == tiles[b].x) ? (tiles[a].y < tiles[b].y) : (tiles[a].x < tiles[b].x); + case TILE_RIGHT_TO_LEFT: + return (tiles[a].x == tiles[b].x) ? (tiles[a].y < tiles[b].y) : (tiles[a].x > tiles[b].x); + case TILE_TOP_TO_BOTTOM: + return (tiles[a].y == tiles[b].y) ? (tiles[a].x < tiles[b].x) : (tiles[a].y > tiles[b].y); + case TILE_BOTTOM_TO_TOP: + default: + return (tiles[a].y == tiles[b].y) ? (tiles[a].x < tiles[b].x) : (tiles[a].y < tiles[b].y); + } + } + + protected: + TileOrder order; + int2 center; + Tile *tiles; }; inline int2 hilbert_index_to_pos(int n, int d) { - int2 r, xy = make_int2(0, 0); - for(int s = 1; s < n; s *= 2) { - r.x = (d >> 1) & 1; - r.y = (d ^ r.x) & 1; - if(!r.y) { - if(r.x) { - xy = make_int2(s-1, s-1) - xy; - } - swap(xy.x, xy.y); - } - xy += r*make_int2(s, s); - d >>= 2; - } - return xy; + int2 r, xy = make_int2(0, 0); + for (int s = 1; s < n; s *= 2) { + r.x = (d >> 1) & 1; + r.y = (d ^ r.x) & 1; + if (!r.y) { + if (r.x) { + xy = make_int2(s - 1, s - 1) - xy; + } + swap(xy.x, xy.y); + } + xy += r * make_int2(s, s); + d >>= 2; + } + return xy; } enum SpiralDirection { - DIRECTION_UP, - DIRECTION_LEFT, - DIRECTION_DOWN, - DIRECTION_RIGHT, + DIRECTION_UP, + DIRECTION_LEFT, + DIRECTION_DOWN, + DIRECTION_RIGHT, }; -} /* namespace */ - -TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int start_resolution_, - bool preserve_tile_device_, bool background_, TileOrder tile_order_, - int num_devices_, int pixel_size_) +} /* namespace */ + +TileManager::TileManager(bool progressive_, + int num_samples_, + int2 tile_size_, + int start_resolution_, + bool preserve_tile_device_, + bool background_, + TileOrder tile_order_, + int num_devices_, + int pixel_size_) { - progressive = progressive_; - tile_size = tile_size_; - tile_order = tile_order_; - start_resolution = start_resolution_; - pixel_size = pixel_size_; - num_samples = num_samples_; - num_devices = num_devices_; - preserve_tile_device = preserve_tile_device_; - background = background_; - schedule_denoising = false; - - range_start_sample = 0; - range_num_samples = -1; - - BufferParams buffer_params; - reset(buffer_params, 0); + progressive = progressive_; + tile_size = tile_size_; + tile_order = tile_order_; + start_resolution = start_resolution_; + pixel_size = pixel_size_; + num_samples = num_samples_; + num_devices = num_devices_; + preserve_tile_device = preserve_tile_device_; + background = background_; + schedule_denoising = false; + + range_start_sample = 0; + range_num_samples = -1; + + BufferParams buffer_params; + reset(buffer_params, 0); } TileManager::~TileManager() @@ -116,422 +120,422 @@ TileManager::~TileManager() void TileManager::device_free() { - if(schedule_denoising || progressive) { - for(int i = 0; i < state.tiles.size(); i++) { - delete state.tiles[i].buffers; - state.tiles[i].buffers = NULL; - } - } - - state.tiles.clear(); + if (schedule_denoising || progressive) { + for (int i = 0; i < state.tiles.size(); i++) { + delete state.tiles[i].buffers; + state.tiles[i].buffers = NULL; + } + } + + state.tiles.clear(); } static int get_divider(int w, int h, int start_resolution) { - int divider = 1; - if(start_resolution != INT_MAX) { - while(w*h > start_resolution*start_resolution) { - w = max(1, w/2); - h = max(1, h/2); - - divider <<= 1; - } - } - return divider; + int divider = 1; + if (start_resolution != INT_MAX) { + while (w * h > start_resolution * start_resolution) { + w = max(1, w / 2); + h = max(1, h / 2); + + divider <<= 1; + } + } + return divider; } -void TileManager::reset(BufferParams& params_, int num_samples_) +void TileManager::reset(BufferParams ¶ms_, int num_samples_) { - params = params_; - - set_samples(num_samples_); - - state.buffer = BufferParams(); - state.sample = range_start_sample - 1; - state.num_tiles = 0; - state.num_samples = 0; - state.resolution_divider = get_divider(params.width, params.height, start_resolution); - state.render_tiles.clear(); - state.denoising_tiles.clear(); - device_free(); + params = params_; + + set_samples(num_samples_); + + state.buffer = BufferParams(); + state.sample = range_start_sample - 1; + state.num_tiles = 0; + state.num_samples = 0; + state.resolution_divider = get_divider(params.width, params.height, start_resolution); + state.render_tiles.clear(); + state.denoising_tiles.clear(); + device_free(); } void TileManager::set_samples(int num_samples_) { - num_samples = num_samples_; - - /* No real progress indication is possible when using unlimited samples. */ - if(num_samples == INT_MAX) { - state.total_pixel_samples = 0; - } - else { - uint64_t pixel_samples = 0; - /* While rendering in the viewport, the initial preview resolution is increased to the native resolution - * before the actual rendering begins. Therefore, additional pixel samples will be rendered. */ - int divider = max(get_divider(params.width, params.height, start_resolution) / 2, pixel_size); - while(divider > pixel_size) { - int image_w = max(1, params.width/divider); - int image_h = max(1, params.height/divider); - pixel_samples += image_w * image_h; - divider >>= 1; - } - - int image_w = max(1, params.width/divider); - int image_h = max(1, params.height/divider); - state.total_pixel_samples = pixel_samples + (uint64_t)get_num_effective_samples() * image_w*image_h; - if(schedule_denoising) { - state.total_pixel_samples += params.width*params.height; - } - } + num_samples = num_samples_; + + /* No real progress indication is possible when using unlimited samples. */ + if (num_samples == INT_MAX) { + state.total_pixel_samples = 0; + } + else { + uint64_t pixel_samples = 0; + /* While rendering in the viewport, the initial preview resolution is increased to the native resolution + * before the actual rendering begins. Therefore, additional pixel samples will be rendered. */ + int divider = max(get_divider(params.width, params.height, start_resolution) / 2, pixel_size); + while (divider > pixel_size) { + int image_w = max(1, params.width / divider); + int image_h = max(1, params.height / divider); + pixel_samples += image_w * image_h; + divider >>= 1; + } + + int image_w = max(1, params.width / divider); + int image_h = max(1, params.height / divider); + state.total_pixel_samples = pixel_samples + + (uint64_t)get_num_effective_samples() * image_w * image_h; + if (schedule_denoising) { + state.total_pixel_samples += params.width * params.height; + } + } } /* If sliced is false, splits image into tiles and assigns equal amount of tiles to every render device. * If sliced is true, slice image into as much pieces as how many devices are rendering this image. */ int TileManager::gen_tiles(bool sliced) { - int resolution = state.resolution_divider; - int image_w = max(1, params.width/resolution); - int image_h = max(1, params.height/resolution); - int2 center = make_int2(image_w/2, image_h/2); - - int num_logical_devices = preserve_tile_device? num_devices: 1; - int num = min(image_h, num_logical_devices); - int slice_num = sliced? num: 1; - int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x); - - device_free(); - state.render_tiles.clear(); - state.denoising_tiles.clear(); - state.render_tiles.resize(num); - state.denoising_tiles.resize(num); - state.tile_stride = tile_w; - vector<list<int> >::iterator tile_list; - tile_list = state.render_tiles.begin(); - - if(tile_order == TILE_HILBERT_SPIRAL) { - assert(!sliced); - - int tile_h = (tile_size.y >= image_h) ? 1 : divide_up(image_h, tile_size.y); - state.tiles.resize(tile_w*tile_h); - - /* Size of blocks in tiles, must be a power of 2 */ - const int hilbert_size = (max(tile_size.x, tile_size.y) <= 12)? 8: 4; - - int tiles_per_device = divide_up(tile_w * tile_h, num); - int cur_device = 0, cur_tiles = 0; - - int2 block_size = tile_size * make_int2(hilbert_size, hilbert_size); - /* Number of blocks to fill the image */ - int blocks_x = (block_size.x >= image_w)? 1: divide_up(image_w, block_size.x); - int blocks_y = (block_size.y >= image_h)? 1: divide_up(image_h, block_size.y); - int n = max(blocks_x, blocks_y) | 0x1; /* Side length of the spiral (must be odd) */ - /* Offset of spiral (to keep it centered) */ - int2 offset = make_int2((image_w - n*block_size.x)/2, (image_h - n*block_size.y)/2); - offset = (offset / tile_size) * tile_size; /* Round to tile border. */ - - int2 block = make_int2(0, 0); /* Current block */ - SpiralDirection prev_dir = DIRECTION_UP, dir = DIRECTION_UP; - for(int i = 0;;) { - /* Generate the tiles in the current block. */ - for(int hilbert_index = 0; hilbert_index < hilbert_size*hilbert_size; hilbert_index++) { - int2 tile, hilbert_pos = hilbert_index_to_pos(hilbert_size, hilbert_index); - /* Rotate block according to spiral direction. */ - if(prev_dir == DIRECTION_UP && dir == DIRECTION_UP) { - tile = make_int2(hilbert_pos.y, hilbert_pos.x); - } - else if(dir == DIRECTION_LEFT || prev_dir == DIRECTION_LEFT) { - tile = hilbert_pos; - } - else if(dir == DIRECTION_DOWN) { - tile = make_int2(hilbert_size-1-hilbert_pos.y, hilbert_size-1-hilbert_pos.x); - } - else { - tile = make_int2(hilbert_size-1-hilbert_pos.x, hilbert_size-1-hilbert_pos.y); - } - - int2 pos = block*block_size + tile*tile_size + offset; - /* Only add tiles which are in the image (tiles outside of the image can be generated since the spiral is always square). */ - if(pos.x >= 0 && pos.y >= 0 && pos.x < image_w && pos.y < image_h) { - int w = min(tile_size.x, image_w - pos.x); - int h = min(tile_size.y, image_h - pos.y); - int2 ipos = pos / tile_size; - int idx = ipos.y*tile_w + ipos.x; - state.tiles[idx] = Tile(idx, pos.x, pos.y, w, h, cur_device, Tile::RENDER); - tile_list->push_front(idx); - cur_tiles++; - - if(cur_tiles == tiles_per_device) { - tile_list++; - cur_tiles = 0; - cur_device++; - } - } - } - - /* Stop as soon as the spiral has reached the center block. */ - if(block.x == (n-1)/2 && block.y == (n-1)/2) - break; - - /* Advance to next block. */ - prev_dir = dir; - switch(dir) { - case DIRECTION_UP: - block.y++; - if(block.y == (n-i-1)) { - dir = DIRECTION_LEFT; - } - break; - case DIRECTION_LEFT: - block.x++; - if(block.x == (n-i-1)) { - dir = DIRECTION_DOWN; - } - break; - case DIRECTION_DOWN: - block.y--; - if(block.y == i) { - dir = DIRECTION_RIGHT; - } - break; - case DIRECTION_RIGHT: - block.x--; - if(block.x == i+1) { - dir = DIRECTION_UP; - i++; - } - break; - } - } - return tile_w*tile_h; - } - - int idx = 0; - for(int slice = 0; slice < slice_num; slice++) { - int slice_y = (image_h/slice_num)*slice; - int slice_h = (slice == slice_num-1)? image_h - slice*(image_h/slice_num): image_h/slice_num; - - int tile_h = (tile_size.y >= slice_h)? 1: divide_up(slice_h, tile_size.y); - - int tiles_per_device = divide_up(tile_w * tile_h, num); - int cur_device = 0, cur_tiles = 0; - - for(int tile_y = 0; tile_y < tile_h; tile_y++) { - for(int tile_x = 0; tile_x < tile_w; tile_x++, idx++) { - int x = tile_x * tile_size.x; - int y = tile_y * tile_size.y; - int w = (tile_x == tile_w-1)? image_w - x: tile_size.x; - int h = (tile_y == tile_h-1)? slice_h - y: tile_size.y; - - state.tiles.push_back(Tile(idx, x, y + slice_y, w, h, sliced? slice: cur_device, Tile::RENDER)); - tile_list->push_back(idx); - - if(!sliced) { - cur_tiles++; - - if(cur_tiles == tiles_per_device) { - /* Tiles are already generated in Bottom-to-Top order, so no sort is necessary in that case. */ - if(tile_order != TILE_BOTTOM_TO_TOP) { - tile_list->sort(TileComparator(tile_order, center, &state.tiles[0])); - } - tile_list++; - cur_tiles = 0; - cur_device++; - } - } - } - } - if(sliced) { - tile_list++; - } - } - - return idx; + int resolution = state.resolution_divider; + int image_w = max(1, params.width / resolution); + int image_h = max(1, params.height / resolution); + int2 center = make_int2(image_w / 2, image_h / 2); + + int num_logical_devices = preserve_tile_device ? num_devices : 1; + int num = min(image_h, num_logical_devices); + int slice_num = sliced ? num : 1; + int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x); + + device_free(); + state.render_tiles.clear(); + state.denoising_tiles.clear(); + state.render_tiles.resize(num); + state.denoising_tiles.resize(num); + state.tile_stride = tile_w; + vector<list<int>>::iterator tile_list; + tile_list = state.render_tiles.begin(); + + if (tile_order == TILE_HILBERT_SPIRAL) { + assert(!sliced); + + int tile_h = (tile_size.y >= image_h) ? 1 : divide_up(image_h, tile_size.y); + state.tiles.resize(tile_w * tile_h); + + /* Size of blocks in tiles, must be a power of 2 */ + const int hilbert_size = (max(tile_size.x, tile_size.y) <= 12) ? 8 : 4; + + int tiles_per_device = divide_up(tile_w * tile_h, num); + int cur_device = 0, cur_tiles = 0; + + int2 block_size = tile_size * make_int2(hilbert_size, hilbert_size); + /* Number of blocks to fill the image */ + int blocks_x = (block_size.x >= image_w) ? 1 : divide_up(image_w, block_size.x); + int blocks_y = (block_size.y >= image_h) ? 1 : divide_up(image_h, block_size.y); + int n = max(blocks_x, blocks_y) | 0x1; /* Side length of the spiral (must be odd) */ + /* Offset of spiral (to keep it centered) */ + int2 offset = make_int2((image_w - n * block_size.x) / 2, (image_h - n * block_size.y) / 2); + offset = (offset / tile_size) * tile_size; /* Round to tile border. */ + + int2 block = make_int2(0, 0); /* Current block */ + SpiralDirection prev_dir = DIRECTION_UP, dir = DIRECTION_UP; + for (int i = 0;;) { + /* Generate the tiles in the current block. */ + for (int hilbert_index = 0; hilbert_index < hilbert_size * hilbert_size; hilbert_index++) { + int2 tile, hilbert_pos = hilbert_index_to_pos(hilbert_size, hilbert_index); + /* Rotate block according to spiral direction. */ + if (prev_dir == DIRECTION_UP && dir == DIRECTION_UP) { + tile = make_int2(hilbert_pos.y, hilbert_pos.x); + } + else if (dir == DIRECTION_LEFT || prev_dir == DIRECTION_LEFT) { + tile = hilbert_pos; + } + else if (dir == DIRECTION_DOWN) { + tile = make_int2(hilbert_size - 1 - hilbert_pos.y, hilbert_size - 1 - hilbert_pos.x); + } + else { + tile = make_int2(hilbert_size - 1 - hilbert_pos.x, hilbert_size - 1 - hilbert_pos.y); + } + + int2 pos = block * block_size + tile * tile_size + offset; + /* Only add tiles which are in the image (tiles outside of the image can be generated since the spiral is always square). */ + if (pos.x >= 0 && pos.y >= 0 && pos.x < image_w && pos.y < image_h) { + int w = min(tile_size.x, image_w - pos.x); + int h = min(tile_size.y, image_h - pos.y); + int2 ipos = pos / tile_size; + int idx = ipos.y * tile_w + ipos.x; + state.tiles[idx] = Tile(idx, pos.x, pos.y, w, h, cur_device, Tile::RENDER); + tile_list->push_front(idx); + cur_tiles++; + + if (cur_tiles == tiles_per_device) { + tile_list++; + cur_tiles = 0; + cur_device++; + } + } + } + + /* Stop as soon as the spiral has reached the center block. */ + if (block.x == (n - 1) / 2 && block.y == (n - 1) / 2) + break; + + /* Advance to next block. */ + prev_dir = dir; + switch (dir) { + case DIRECTION_UP: + block.y++; + if (block.y == (n - i - 1)) { + dir = DIRECTION_LEFT; + } + break; + case DIRECTION_LEFT: + block.x++; + if (block.x == (n - i - 1)) { + dir = DIRECTION_DOWN; + } + break; + case DIRECTION_DOWN: + block.y--; + if (block.y == i) { + dir = DIRECTION_RIGHT; + } + break; + case DIRECTION_RIGHT: + block.x--; + if (block.x == i + 1) { + dir = DIRECTION_UP; + i++; + } + break; + } + } + return tile_w * tile_h; + } + + int idx = 0; + for (int slice = 0; slice < slice_num; slice++) { + int slice_y = (image_h / slice_num) * slice; + int slice_h = (slice == slice_num - 1) ? image_h - slice * (image_h / slice_num) : + image_h / slice_num; + + int tile_h = (tile_size.y >= slice_h) ? 1 : divide_up(slice_h, tile_size.y); + + int tiles_per_device = divide_up(tile_w * tile_h, num); + int cur_device = 0, cur_tiles = 0; + + for (int tile_y = 0; tile_y < tile_h; tile_y++) { + for (int tile_x = 0; tile_x < tile_w; tile_x++, idx++) { + int x = tile_x * tile_size.x; + int y = tile_y * tile_size.y; + int w = (tile_x == tile_w - 1) ? image_w - x : tile_size.x; + int h = (tile_y == tile_h - 1) ? slice_h - y : tile_size.y; + + state.tiles.push_back( + Tile(idx, x, y + slice_y, w, h, sliced ? slice : cur_device, Tile::RENDER)); + tile_list->push_back(idx); + + if (!sliced) { + cur_tiles++; + + if (cur_tiles == tiles_per_device) { + /* Tiles are already generated in Bottom-to-Top order, so no sort is necessary in that case. */ + if (tile_order != TILE_BOTTOM_TO_TOP) { + tile_list->sort(TileComparator(tile_order, center, &state.tiles[0])); + } + tile_list++; + cur_tiles = 0; + cur_device++; + } + } + } + } + if (sliced) { + tile_list++; + } + } + + return idx; } void TileManager::gen_render_tiles() { - /* Regenerate just the render tiles for progressive render. */ - foreach(Tile& tile, state.tiles) { - state.render_tiles[tile.device].push_back(tile.index); - } + /* Regenerate just the render tiles for progressive render. */ + foreach (Tile &tile, state.tiles) { + state.render_tiles[tile.device].push_back(tile.index); + } } void TileManager::set_tiles() { - int resolution = state.resolution_divider; - int image_w = max(1, params.width/resolution); - int image_h = max(1, params.height/resolution); + int resolution = state.resolution_divider; + int image_w = max(1, params.width / resolution); + int image_h = max(1, params.height / resolution); - state.num_tiles = gen_tiles(!background); + state.num_tiles = gen_tiles(!background); - state.buffer.width = image_w; - state.buffer.height = image_h; + state.buffer.width = image_w; + state.buffer.height = image_h; - state.buffer.full_x = params.full_x/resolution; - state.buffer.full_y = params.full_y/resolution; - state.buffer.full_width = max(1, params.full_width/resolution); - state.buffer.full_height = max(1, params.full_height/resolution); + state.buffer.full_x = params.full_x / resolution; + state.buffer.full_y = params.full_y / resolution; + state.buffer.full_width = max(1, params.full_width / resolution); + state.buffer.full_height = max(1, params.full_height / resolution); } int TileManager::get_neighbor_index(int index, int neighbor) { - static const int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1, 0}, dy[] = {-1, -1, -1, 0, 0, 1, 1, 1, 0}; + static const int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1, 0}, dy[] = {-1, -1, -1, 0, 0, 1, 1, 1, 0}; - int resolution = state.resolution_divider; - int image_w = max(1, params.width/resolution); - int image_h = max(1, params.height/resolution); - int tile_w = (tile_size.x >= image_w)? 1: divide_up(image_w, tile_size.x); - int tile_h = (tile_size.y >= image_h)? 1: divide_up(image_h, tile_size.y); + int resolution = state.resolution_divider; + int image_w = max(1, params.width / resolution); + int image_h = max(1, params.height / resolution); + int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x); + int tile_h = (tile_size.y >= image_h) ? 1 : divide_up(image_h, tile_size.y); - int nx = state.tiles[index].x/tile_size.x + dx[neighbor], ny = state.tiles[index].y/tile_size.y + dy[neighbor]; - if(nx < 0 || ny < 0 || nx >= tile_w || ny >= tile_h) - return -1; + int nx = state.tiles[index].x / tile_size.x + dx[neighbor], + ny = state.tiles[index].y / tile_size.y + dy[neighbor]; + if (nx < 0 || ny < 0 || nx >= tile_w || ny >= tile_h) + return -1; - return ny*state.tile_stride + nx; + return ny * state.tile_stride + nx; } /* Checks whether all neighbors of a tile (as well as the tile itself) are at least at state min_state. */ bool TileManager::check_neighbor_state(int index, Tile::State min_state) { - if(index < 0 || state.tiles[index].state < min_state) { - return false; - } - for(int neighbor = 0; neighbor < 9; neighbor++) { - int nindex = get_neighbor_index(index, neighbor); - /* Out-of-bounds tiles don't matter. */ - if(nindex >= 0 && state.tiles[nindex].state < min_state) { - return false; - } - } - - return true; + if (index < 0 || state.tiles[index].state < min_state) { + return false; + } + for (int neighbor = 0; neighbor < 9; neighbor++) { + int nindex = get_neighbor_index(index, neighbor); + /* Out-of-bounds tiles don't matter. */ + if (nindex >= 0 && state.tiles[nindex].state < min_state) { + return false; + } + } + + return true; } /* Returns whether the tile should be written (and freed if no denoising is used) instead of updating. */ bool TileManager::finish_tile(int index, bool &delete_tile) { - delete_tile = false; - - if(progressive) { - return true; - } - - switch(state.tiles[index].state) { - case Tile::RENDER: - { - if(!schedule_denoising) { - state.tiles[index].state = Tile::DONE; - delete_tile = true; - return true; - } - state.tiles[index].state = Tile::RENDERED; - /* For each neighbor and the tile itself, check whether all of its neighbors have been rendered. If yes, it can be denoised. */ - for(int neighbor = 0; neighbor < 9; neighbor++) { - int nindex = get_neighbor_index(index, neighbor); - if(check_neighbor_state(nindex, Tile::RENDERED)) { - state.tiles[nindex].state = Tile::DENOISE; - state.denoising_tiles[state.tiles[nindex].device].push_back(nindex); - } - } - return false; - } - case Tile::DENOISE: - { - state.tiles[index].state = Tile::DENOISED; - /* For each neighbor and the tile itself, check whether all of its neighbors have been denoised. If yes, it can be freed. */ - for(int neighbor = 0; neighbor < 9; neighbor++) { - int nindex = get_neighbor_index(index, neighbor); - if(check_neighbor_state(nindex, Tile::DENOISED)) { - state.tiles[nindex].state = Tile::DONE; - /* It can happen that the tile just finished denoising and already can be freed here. - * However, in that case it still has to be written before deleting, so we can't delete it yet. */ - if(neighbor == 8) { - delete_tile = true; - } - else { - delete state.tiles[nindex].buffers; - state.tiles[nindex].buffers = NULL; - } - } - } - return true; - } - default: - assert(false); - return true; - } + delete_tile = false; + + if (progressive) { + return true; + } + + switch (state.tiles[index].state) { + case Tile::RENDER: { + if (!schedule_denoising) { + state.tiles[index].state = Tile::DONE; + delete_tile = true; + return true; + } + state.tiles[index].state = Tile::RENDERED; + /* For each neighbor and the tile itself, check whether all of its neighbors have been rendered. If yes, it can be denoised. */ + for (int neighbor = 0; neighbor < 9; neighbor++) { + int nindex = get_neighbor_index(index, neighbor); + if (check_neighbor_state(nindex, Tile::RENDERED)) { + state.tiles[nindex].state = Tile::DENOISE; + state.denoising_tiles[state.tiles[nindex].device].push_back(nindex); + } + } + return false; + } + case Tile::DENOISE: { + state.tiles[index].state = Tile::DENOISED; + /* For each neighbor and the tile itself, check whether all of its neighbors have been denoised. If yes, it can be freed. */ + for (int neighbor = 0; neighbor < 9; neighbor++) { + int nindex = get_neighbor_index(index, neighbor); + if (check_neighbor_state(nindex, Tile::DENOISED)) { + state.tiles[nindex].state = Tile::DONE; + /* It can happen that the tile just finished denoising and already can be freed here. + * However, in that case it still has to be written before deleting, so we can't delete it yet. */ + if (neighbor == 8) { + delete_tile = true; + } + else { + delete state.tiles[nindex].buffers; + state.tiles[nindex].buffers = NULL; + } + } + } + return true; + } + default: + assert(false); + return true; + } } -bool TileManager::next_tile(Tile* &tile, int device) +bool TileManager::next_tile(Tile *&tile, int device) { - int logical_device = preserve_tile_device? device: 0; + int logical_device = preserve_tile_device ? device : 0; - if(logical_device >= state.render_tiles.size()) - return false; + if (logical_device >= state.render_tiles.size()) + return false; - if(!state.denoising_tiles[logical_device].empty()) { - int idx = state.denoising_tiles[logical_device].front(); - state.denoising_tiles[logical_device].pop_front(); - tile = &state.tiles[idx]; - return true; - } + if (!state.denoising_tiles[logical_device].empty()) { + int idx = state.denoising_tiles[logical_device].front(); + state.denoising_tiles[logical_device].pop_front(); + tile = &state.tiles[idx]; + return true; + } - if(state.render_tiles[logical_device].empty()) - return false; + if (state.render_tiles[logical_device].empty()) + return false; - int idx = state.render_tiles[logical_device].front(); - state.render_tiles[logical_device].pop_front(); - tile = &state.tiles[idx]; - return true; + int idx = state.render_tiles[logical_device].front(); + state.render_tiles[logical_device].pop_front(); + tile = &state.tiles[idx]; + return true; } bool TileManager::done() { - int end_sample = (range_num_samples == -1) - ? num_samples - : range_start_sample + range_num_samples; - return (state.resolution_divider == pixel_size) && - (state.sample+state.num_samples >= end_sample); + int end_sample = (range_num_samples == -1) ? num_samples : + range_start_sample + range_num_samples; + return (state.resolution_divider == pixel_size) && + (state.sample + state.num_samples >= end_sample); } bool TileManager::next() { - if(done()) - return false; - - if(progressive && state.resolution_divider > pixel_size) { - state.sample = 0; - state.resolution_divider = max(state.resolution_divider/2, pixel_size); - state.num_samples = 1; - set_tiles(); - } - else { - state.sample++; - - if(progressive) - state.num_samples = 1; - else if(range_num_samples == -1) - state.num_samples = num_samples; - else - state.num_samples = range_num_samples; - - state.resolution_divider = pixel_size; - - if(state.sample == range_start_sample) { - set_tiles(); - } - else { - gen_render_tiles(); - } - } - - return true; + if (done()) + return false; + + if (progressive && state.resolution_divider > pixel_size) { + state.sample = 0; + state.resolution_divider = max(state.resolution_divider / 2, pixel_size); + state.num_samples = 1; + set_tiles(); + } + else { + state.sample++; + + if (progressive) + state.num_samples = 1; + else if (range_num_samples == -1) + state.num_samples = num_samples; + else + state.num_samples = range_num_samples; + + state.resolution_divider = pixel_size; + + if (state.sample == range_start_sample) { + set_tiles(); + } + else { + gen_render_tiles(); + } + } + + return true; } int TileManager::get_num_effective_samples() { - return (range_num_samples == -1) ? num_samples - : range_num_samples; + return (range_num_samples == -1) ? num_samples : range_num_samples; } CCL_NAMESPACE_END diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index 2835c793073..017c1af0ead 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -27,131 +27,144 @@ CCL_NAMESPACE_BEGIN /* Tile */ class Tile { -public: - int index; - int x, y, w, h; - int device; - /* RENDER: The tile has to be rendered. - * RENDERED: The tile has been rendered, but can't be denoised yet (waiting for neighbors). - * DENOISE: The tile can be denoised now. - * DENOISED: The tile has been denoised, but can't be freed yet (waiting for neighbors). - * DONE: The tile is finished and has been freed. */ - typedef enum { RENDER = 0, RENDERED, DENOISE, DENOISED, DONE } State; - State state; - RenderBuffers *buffers; - - Tile() - {} - - Tile(int index_, int x_, int y_, int w_, int h_, int device_, State state_ = RENDER) - : index(index_), x(x_), y(y_), w(w_), h(h_), device(device_), state(state_), buffers(NULL) {} + public: + int index; + int x, y, w, h; + int device; + /* RENDER: The tile has to be rendered. + * RENDERED: The tile has been rendered, but can't be denoised yet (waiting for neighbors). + * DENOISE: The tile can be denoised now. + * DENOISED: The tile has been denoised, but can't be freed yet (waiting for neighbors). + * DONE: The tile is finished and has been freed. */ + typedef enum { RENDER = 0, RENDERED, DENOISE, DENOISED, DONE } State; + State state; + RenderBuffers *buffers; + + Tile() + { + } + + Tile(int index_, int x_, int y_, int w_, int h_, int device_, State state_ = RENDER) + : index(index_), x(x_), y(y_), w(w_), h(h_), device(device_), state(state_), buffers(NULL) + { + } }; /* Tile order */ /* Note: this should match enum_tile_order in properties.py */ enum TileOrder { - TILE_CENTER = 0, - TILE_RIGHT_TO_LEFT = 1, - TILE_LEFT_TO_RIGHT = 2, - TILE_TOP_TO_BOTTOM = 3, - TILE_BOTTOM_TO_TOP = 4, - TILE_HILBERT_SPIRAL = 5, + TILE_CENTER = 0, + TILE_RIGHT_TO_LEFT = 1, + TILE_LEFT_TO_RIGHT = 2, + TILE_TOP_TO_BOTTOM = 3, + TILE_BOTTOM_TO_TOP = 4, + TILE_HILBERT_SPIRAL = 5, }; /* Tile Manager */ class TileManager { -public: - BufferParams params; - - struct State { - vector<Tile> tiles; - int tile_stride; - BufferParams buffer; - int sample; - int num_samples; - int resolution_divider; - int num_tiles; - - /* Total samples over all pixels: Generally num_samples*num_pixels, - * but can be higher due to the initial resolution division for previews. */ - uint64_t total_pixel_samples; - - /* These lists contain the indices of the tiles to be rendered/denoised and are used - * when acquiring a new tile for the device. - * Each list in each vector is for one logical device. */ - vector<list<int> > render_tiles; - vector<list<int> > denoising_tiles; - } state; - - int num_samples; - - TileManager(bool progressive, int num_samples, int2 tile_size, int start_resolution, - bool preserve_tile_device, bool background, TileOrder tile_order, int num_devices = 1, int pixel_size = 1); - ~TileManager(); - - void device_free(); - void reset(BufferParams& params, int num_samples); - void set_samples(int num_samples); - bool next(); - bool next_tile(Tile* &tile, int device = 0); - bool finish_tile(int index, bool& delete_tile); - bool done(); - - void set_tile_order(TileOrder tile_order_) { tile_order = tile_order_; } - - /* ** Sample range rendering. ** */ - - /* Start sample in the range. */ - int range_start_sample; - - /* Number to samples in the rendering range. */ - int range_num_samples; - - /* Get number of actual samples to render. */ - int get_num_effective_samples(); - - /* Schedule tiles for denoising after they've been rendered. */ - bool schedule_denoising; -protected: - - void set_tiles(); - - bool progressive; - int2 tile_size; - TileOrder tile_order; - int start_resolution; - int pixel_size; - int num_devices; - - /* in some cases it is important that the same tile will be returned for the same - * device it was originally generated for (i.e. viewport rendering when buffer is - * allocating once for tile and then always used by it) - * - * in other cases any tile could be handled by any device (i.e. final rendering - * without progressive refine) - */ - bool preserve_tile_device; - - /* for background render tiles should exactly match render parts generated from - * blender side, which means image first gets split into tiles and then tiles are - * assigning to render devices - * - * however viewport rendering expects tiles to be allocated in a special way, - * meaning image is being sliced horizontally first and every device handles - * it's own slice - */ - bool background; - - /* Generate tile list, return number of tiles. */ - int gen_tiles(bool sliced); - void gen_render_tiles(); - - int get_neighbor_index(int index, int neighbor); - bool check_neighbor_state(int index, Tile::State state); + public: + BufferParams params; + + struct State { + vector<Tile> tiles; + int tile_stride; + BufferParams buffer; + int sample; + int num_samples; + int resolution_divider; + int num_tiles; + + /* Total samples over all pixels: Generally num_samples*num_pixels, + * but can be higher due to the initial resolution division for previews. */ + uint64_t total_pixel_samples; + + /* These lists contain the indices of the tiles to be rendered/denoised and are used + * when acquiring a new tile for the device. + * Each list in each vector is for one logical device. */ + vector<list<int>> render_tiles; + vector<list<int>> denoising_tiles; + } state; + + int num_samples; + + TileManager(bool progressive, + int num_samples, + int2 tile_size, + int start_resolution, + bool preserve_tile_device, + bool background, + TileOrder tile_order, + int num_devices = 1, + int pixel_size = 1); + ~TileManager(); + + void device_free(); + void reset(BufferParams ¶ms, int num_samples); + void set_samples(int num_samples); + bool next(); + bool next_tile(Tile *&tile, int device = 0); + bool finish_tile(int index, bool &delete_tile); + bool done(); + + void set_tile_order(TileOrder tile_order_) + { + tile_order = tile_order_; + } + + /* ** Sample range rendering. ** */ + + /* Start sample in the range. */ + int range_start_sample; + + /* Number to samples in the rendering range. */ + int range_num_samples; + + /* Get number of actual samples to render. */ + int get_num_effective_samples(); + + /* Schedule tiles for denoising after they've been rendered. */ + bool schedule_denoising; + + protected: + void set_tiles(); + + bool progressive; + int2 tile_size; + TileOrder tile_order; + int start_resolution; + int pixel_size; + int num_devices; + + /* in some cases it is important that the same tile will be returned for the same + * device it was originally generated for (i.e. viewport rendering when buffer is + * allocating once for tile and then always used by it) + * + * in other cases any tile could be handled by any device (i.e. final rendering + * without progressive refine) + */ + bool preserve_tile_device; + + /* for background render tiles should exactly match render parts generated from + * blender side, which means image first gets split into tiles and then tiles are + * assigning to render devices + * + * however viewport rendering expects tiles to be allocated in a special way, + * meaning image is being sliced horizontally first and every device handles + * it's own slice + */ + bool background; + + /* Generate tile list, return number of tiles. */ + int gen_tiles(bool sliced); + void gen_render_tiles(); + + int get_neighbor_index(int index, int neighbor); + bool check_neighbor_state(int index, Tile::State state); }; CCL_NAMESPACE_END -#endif /* __TILE_H__ */ +#endif /* __TILE_H__ */ |