Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPascal Schoen <pascal_schoen@gmx.net>2016-08-03 12:42:02 +0300
committerPascal Schoen <pascal_schoen@gmx.net>2016-08-03 12:42:02 +0300
commit81f6c06b1f53180bf32a5c11ac1fa64e2b6abf52 (patch)
treec7ad4920e48e0eb529e2064fd0d3813c29d5383b /intern/cycles/render
parentece5a08e0d6e51a83c223ea87346134216e5b34e (diff)
parent7065022f7aa23ba13d2999e1e40162a8f480af0e (diff)
Merge branch 'master' into cycles_disney_brdf
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/CMakeLists.txt3
-rw-r--r--intern/cycles/render/attribute.cpp102
-rw-r--r--intern/cycles/render/attribute.h20
-rw-r--r--intern/cycles/render/background.cpp9
-rw-r--r--intern/cycles/render/background.h1
-rw-r--r--intern/cycles/render/bake.cpp2
-rw-r--r--intern/cycles/render/camera.cpp184
-rw-r--r--intern/cycles/render/camera.h8
-rw-r--r--intern/cycles/render/constant_fold.cpp354
-rw-r--r--intern/cycles/render/constant_fold.h70
-rw-r--r--intern/cycles/render/curves.h34
-rw-r--r--intern/cycles/render/film.cpp2
-rw-r--r--intern/cycles/render/graph.cpp330
-rw-r--r--intern/cycles/render/graph.h124
-rw-r--r--intern/cycles/render/image.cpp358
-rw-r--r--intern/cycles/render/image.h12
-rw-r--r--intern/cycles/render/integrator.cpp7
-rw-r--r--intern/cycles/render/integrator.h1
-rw-r--r--intern/cycles/render/light.cpp195
-rw-r--r--intern/cycles/render/light.h4
-rw-r--r--intern/cycles/render/mesh.cpp802
-rw-r--r--intern/cycles/render/mesh.h158
-rw-r--r--intern/cycles/render/mesh_displace.cpp9
-rw-r--r--intern/cycles/render/mesh_subdivision.cpp224
-rw-r--r--intern/cycles/render/nodes.cpp3210
-rw-r--r--intern/cycles/render/nodes.h613
-rw-r--r--intern/cycles/render/object.cpp56
-rw-r--r--intern/cycles/render/object.h11
-rw-r--r--intern/cycles/render/osl.cpp356
-rw-r--r--intern/cycles/render/osl.h9
-rw-r--r--intern/cycles/render/particles.cpp11
-rw-r--r--intern/cycles/render/particles.h2
-rw-r--r--intern/cycles/render/scene.cpp17
-rw-r--r--intern/cycles/render/scene.h24
-rw-r--r--intern/cycles/render/session.cpp2
-rw-r--r--intern/cycles/render/shader.cpp20
-rw-r--r--intern/cycles/render/svm.cpp65
-rw-r--r--intern/cycles/render/svm.h6
38 files changed, 4841 insertions, 2574 deletions
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index b14da3e63d0..8eaa9de3874 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SRC
bake.cpp
buffers.cpp
camera.cpp
+ constant_fold.cpp
film.cpp
graph.cpp
image.cpp
@@ -29,6 +30,7 @@ set(SRC
light.cpp
mesh.cpp
mesh_displace.cpp
+ mesh_subdivision.cpp
nodes.cpp
object.cpp
osl.cpp
@@ -49,6 +51,7 @@ set(SRC_HEADERS
background.h
buffers.h
camera.h
+ constant_fold.h
film.h
graph.h
image.h
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index b7de83d89c1..e8ff81fe08e 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -51,13 +51,13 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix);
}
-void Attribute::reserve(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool resize)
+void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only)
{
- if(resize) {
- buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0);
+ if(reserve_only) {
+ buffer.reserve(buffer_size(mesh, prim));
}
else {
- buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys));
+ buffer.resize(buffer_size(mesh, prim), 0);
}
}
@@ -118,6 +118,8 @@ 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 == TypeDesc::TypeMatrix)
@@ -126,10 +128,10 @@ size_t Attribute::data_sizeof() const
return sizeof(float3);
}
-size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const
+size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const
{
size_t size;
-
+
switch(element) {
case ATTR_ELEMENT_OBJECT:
case ATTR_ELEMENT_MESH:
@@ -137,38 +139,54 @@ size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numc
size = 1;
break;
case ATTR_ELEMENT_VERTEX:
- size = numverts;
+ size = mesh->verts.size() + mesh->num_ngons;
+ if(prim == ATTR_PRIM_SUBD) {
+ size -= mesh->num_subd_verts;
+ }
break;
case ATTR_ELEMENT_VERTEX_MOTION:
- size = numverts * (numsteps - 1);
+ 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:
- size = numtris;
+ 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:
- size = numtris*3;
+ 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 = numcurves;
+ size = mesh->num_curves();
break;
case ATTR_ELEMENT_CURVE_KEY:
- size = numkeys;
+ size = mesh->curve_keys.size();
break;
case ATTR_ELEMENT_CURVE_KEY_MOTION:
- size = numkeys * (numsteps - 1);
+ size = mesh->curve_keys.size() * (mesh->motion_steps - 1);
break;
default:
size = 0;
break;
}
-
+
return size;
}
-size_t Attribute::buffer_size(int numverts, int numtris, int numsteps, int numcurves, int numkeys) const
+size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const
{
- return element_size(numverts, numtris, numsteps, numcurves, numkeys)*data_sizeof();
+ return element_size(mesh, prim)*data_sizeof();
}
bool Attribute::same_storage(TypeDesc a, TypeDesc b)
@@ -188,6 +206,29 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b)
return false;
}
+void Attribute::zero_data(void* dst)
+{
+ memset(dst, 0, data_sizeof());
+}
+
+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");
+ }
+}
+
const char *Attribute::standard_name(AttributeStandard std)
{
switch(std) {
@@ -257,13 +298,14 @@ AttributeSet::AttributeSet()
{
triangle_mesh = NULL;
curve_mesh = NULL;
+ subd_mesh = NULL;
}
AttributeSet::~AttributeSet()
{
}
-Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element, bool resize)
+Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
{
Attribute *attr = find(name);
@@ -291,10 +333,12 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme
/* this is weak .. */
if(triangle_mesh)
- attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, resize);
+ attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false);
if(curve_mesh)
- attr->reserve(0, 0, curve_mesh->motion_steps, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), resize);
-
+ attr->resize(curve_mesh, ATTR_PRIM_CURVE, false);
+ if(subd_mesh)
+ attr->resize(subd_mesh, ATTR_PRIM_SUBD, false);
+
return attr;
}
@@ -330,7 +374,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
if(name == ustring())
name = Attribute::standard_name(std);
- if(triangle_mesh) {
+ if(triangle_mesh || subd_mesh) {
switch(std) {
case ATTR_STD_VERTEX_NORMAL:
attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX);
@@ -448,13 +492,15 @@ Attribute *AttributeSet::find(AttributeRequest& req)
return find(req.std);
}
-void AttributeSet::reserve()
+void AttributeSet::resize(bool reserve_only)
{
foreach(Attribute& attr, attributes) {
if(triangle_mesh)
- attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, true);
+ attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only);
if(curve_mesh)
- attr.reserve(0, 0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), true);
+ attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only);
+ if(subd_mesh)
+ attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only);
}
}
@@ -477,6 +523,10 @@ AttributeRequest::AttributeRequest(ustring name_)
curve_type = TypeDesc::TypeFloat;
curve_element = ATTR_ELEMENT_NONE;
curve_offset = 0;
+
+ subd_type = TypeDesc::TypeFloat;
+ subd_element = ATTR_ELEMENT_NONE;
+ subd_offset = 0;
}
AttributeRequest::AttributeRequest(AttributeStandard std_)
@@ -491,6 +541,10 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
curve_type = TypeDesc::TypeFloat;
curve_element = ATTR_ELEMENT_NONE;
curve_offset = 0;
+
+ subd_type = TypeDesc::TypeFloat;
+ subd_element = ATTR_ELEMENT_NONE;
+ subd_offset = 0;
}
/* AttributeRequestSet */
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index 01102d22aaa..e51bdf28d66 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -58,11 +58,11 @@ public:
Attribute() {}
~Attribute();
void set(ustring name, TypeDesc type, AttributeElement element);
- void reserve(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool resize);
+ void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only);
size_t data_sizeof() const;
- size_t element_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const;
- size_t buffer_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) 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; };
float3 *data_float3() { return (float3*)data(); }
@@ -79,6 +79,9 @@ public:
const Transform *data_transform() const { return (const Transform*)data(); }
const VoxelAttribute *data_voxel() const { 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 float3& f);
void add(const uchar4& f);
@@ -99,12 +102,13 @@ class AttributeSet {
public:
Mesh *triangle_mesh;
Mesh *curve_mesh;
+ Mesh *subd_mesh;
list<Attribute> attributes;
AttributeSet();
~AttributeSet();
- Attribute *add(ustring name, TypeDesc type, AttributeElement element, bool resize = true);
+ Attribute *add(ustring name, TypeDesc type, AttributeElement element);
Attribute *find(ustring name) const;
void remove(ustring name);
@@ -114,7 +118,7 @@ public:
Attribute *find(AttributeRequest& req);
- void reserve();
+ void resize(bool reserve_only = false);
void clear();
};
@@ -130,9 +134,9 @@ public:
AttributeStandard std;
/* temporary variables used by MeshManager */
- TypeDesc triangle_type, curve_type;
- AttributeElement triangle_element, curve_element;
- int triangle_offset, curve_offset;
+ TypeDesc triangle_type, curve_type, subd_type;
+ AttributeElement triangle_element, curve_element, subd_element;
+ int triangle_offset, curve_offset, subd_offset;
explicit AttributeRequest(ustring name_);
explicit AttributeRequest(AttributeStandard std);
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index 6f8d1d1d461..8d7d7b847fd 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -32,12 +32,12 @@ NODE_DEFINE(Background)
{
NodeType* type = NodeType::add("background", create);
- SOCKET_INT(ao_factor, "AO Factor", 0.0f);
+ 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_INT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY);
+ SOCKET_UINT(visibility, "Visibility", PATH_RAY_ALL_VISIBILITY);
SOCKET_BOOLEAN(transparent, "Transparent", false);
SOCKET_NODE(shader, "Shader", &Shader::node_type);
@@ -116,6 +116,11 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
}
+bool Background::modified(const Background& background)
+{
+ return !Node::equals(background);
+}
+
void Background::tag_update(Scene *scene)
{
scene->integrator->tag_update(scene);
diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h
index 843655b00a1..8029c6a9e80 100644
--- a/intern/cycles/render/background.h
+++ b/intern/cycles/render/background.h
@@ -50,6 +50,7 @@ public:
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);
};
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 5bf5e5113ef..13310a61761 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -177,7 +177,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
device->mem_alloc(d_input, MEM_READ_ONLY);
device->mem_copy_to(d_input);
- device->mem_alloc(d_output, MEM_WRITE_ONLY);
+ device->mem_alloc(d_output, MEM_READ_WRITE);
DeviceTask task(DeviceTask::SHADER);
task.shader_input = d_input.device_pointer;
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index d992cac5312..a6df656d220 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -30,70 +30,126 @@
CCL_NAMESPACE_BEGIN
static float shutter_curve_eval(float x,
- float shutter_curve[RAMP_TABLE_SIZE])
+ array<float>& shutter_curve)
{
- x *= RAMP_TABLE_SIZE;
+ if (shutter_curve.size() == 0)
+ return 1.0f;
+
+ x *= shutter_curve.size();
int index = (int)x;
float frac = x - index;
- if(index < RAMP_TABLE_SIZE - 1) {
+ if(index < shutter_curve.size() - 1) {
return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
}
else {
- return shutter_curve[RAMP_TABLE_SIZE - 1];
+ 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_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);
+
+ return type;
+}
+
Camera::Camera()
+: Node(node_type)
{
- shuttertime = 1.0f;
- motion_position = MOTION_POSITION_CENTER;
shutter_table_offset = TABLE_OFFSET_INVALID;
- aperturesize = 0.0f;
- focaldistance = 10.0f;
- blades = 0;
- bladesrotation = 0.0f;
-
- matrix = transform_identity();
+ width = 1024;
+ height = 512;
+ resolution = 1;
motion.pre = transform_identity();
motion.post = transform_identity();
use_motion = false;
use_perspective_motion = false;
- aperture_ratio = 1.0f;
-
- type = CAMERA_PERSPECTIVE;
- panorama_type = PANORAMA_EQUIRECTANGULAR;
- fisheye_fov = M_PI_F;
- fisheye_lens = 10.5f;
- latitude_min = -M_PI_2_F;
- latitude_max = M_PI_2_F;
- longitude_min = -M_PI_F;
- longitude_max = M_PI_F;
- fov = M_PI_4_F;
- fov_pre = fov_post = fov;
- stereo_eye = STEREO_NONE;
- interocular_distance = 0.065f;
- convergence_distance = 30.0f * 0.065f;
- use_pole_merge = false;
- pole_merge_angle_from = 60.0f * M_PI_F / 180.0f;
- pole_merge_angle_to = 75.0f * M_PI_F / 180.0f;
-
- sensorwidth = 0.036f;
- sensorheight = 0.024f;
-
- nearclip = 1e-5f;
- farclip = 1e5f;
-
- width = 1024;
- height = 512;
- resolution = 1;
+ shutter_curve.resize(RAMP_TABLE_SIZE);
+ for(int i = 0; i < shutter_curve.size(); ++i) {
+ shutter_curve[i] = 1.0f;
+ }
- viewplane.left = -((float)width/(float)height);
- viewplane.right = (float)width/(float)height;
- viewplane.bottom = -1.0f;
- viewplane.top = 1.0f;
+ compute_auto_viewplane();
screentoworld = transform_identity();
rastertoworld = transform_identity();
@@ -109,16 +165,6 @@ Camera::Camera()
need_device_update = true;
need_flags_update = true;
previous_need_motion = -1;
-
- /* Initialize shutter curve. */
- const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve);
- for(int i = 0; i < num_shutter_points; ++i) {
- shutter_curve[i] = 1.0f;
- }
-
- /* Initialize rolling shutter effect. */
- rolling_shutter_type = ROLLING_SHUTTER_NONE;
- rolling_shutter_duration = 0.1f;
}
Camera::~Camera()
@@ -438,38 +484,14 @@ void Camera::device_free(Device * /*device*/,
bool Camera::modified(const Camera& cam)
{
- return !((shuttertime == cam.shuttertime) &&
- (aperturesize == cam.aperturesize) &&
- (blades == cam.blades) &&
- (bladesrotation == cam.bladesrotation) &&
- (focaldistance == cam.focaldistance) &&
- (type == cam.type) &&
- (fov == cam.fov) &&
- (nearclip == cam.nearclip) &&
- (farclip == cam.farclip) &&
- (sensorwidth == cam.sensorwidth) &&
- (sensorheight == cam.sensorheight) &&
- // modified for progressive render
- // (width == cam.width) &&
- // (height == cam.height) &&
- (viewplane == cam.viewplane) &&
- (border == cam.border) &&
- (matrix == cam.matrix) &&
- (aperture_ratio == cam.aperture_ratio) &&
- (panorama_type == cam.panorama_type) &&
- (fisheye_fov == cam.fisheye_fov) &&
- (fisheye_lens == cam.fisheye_lens) &&
- (latitude_min == cam.latitude_min) &&
- (latitude_max == cam.latitude_max) &&
- (longitude_min == cam.longitude_min) &&
- (longitude_max == cam.longitude_max) &&
- (stereo_eye == cam.stereo_eye));
+ return !Node::equals(cam);
}
bool Camera::motion_modified(const Camera& cam)
{
return !((motion == cam.motion) &&
- (use_motion == cam.use_motion));
+ (use_motion == cam.use_motion) &&
+ (use_perspective_motion == cam.use_perspective_motion));
}
void Camera::tag_update()
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 57b9960e70b..141ef9cccef 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -19,6 +19,8 @@
#include "kernel_types.h"
+#include "node.h"
+
#include "util_boundbox.h"
#include "util_transform.h"
#include "util_types.h"
@@ -35,8 +37,10 @@ class Scene;
* Renderman, and Blender after remapping.
*/
-class Camera {
+class Camera : public Node {
public:
+ NODE_DECLARE;
+
/* Specifies an offset for the shutter's time interval. */
enum MotionPosition {
/* Shutter opens at the current frame. */
@@ -69,7 +73,7 @@ public:
/* motion blur */
float shuttertime;
MotionPosition motion_position;
- float shutter_curve[RAMP_TABLE_SIZE];
+ array<float> shutter_curve;
size_t shutter_table_offset;
/* ** Rolling shutter effect. ** */
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp
new file mode 100644
index 00000000000..073bafce98d
--- /dev/null
+++ b/intern/cycles/render/constant_fold.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "constant_fold.h"
+#include "graph.h"
+
+#include "util_foreach.h"
+#include "util_logging.h"
+
+CCL_NAMESPACE_BEGIN
+
+ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output)
+: graph(graph), node(node), output(output)
+{
+}
+
+bool ConstantFolder::all_inputs_constant() const
+{
+ foreach(ShaderInput *input, node->inputs) {
+ if(input->link) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ConstantFolder::make_constant(float value) const
+{
+ VLOG(1) << "Replacing " << node->name << " with constant " << value << ".";
+ foreach(ShaderInput *sock, output->links) {
+ sock->set(value);
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant(float3 value) const
+{
+ foreach(ShaderInput *sock, output->links) {
+ sock->set(value);
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant_clamp(float value, bool clamp) const
+{
+ 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);
+ }
+
+ 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);
+ }
+}
+
+void ConstantFolder::bypass(ShaderOutput *new_output) const
+{
+ assert(new_output);
+
+ /* 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);
+
+ foreach(ShaderInput *sock, outputs) {
+ graph->connect(new_output, sock);
+ }
+}
+
+void ConstantFolder::discard() const
+{
+ assert(output->type() == SocketType::CLOSURE);
+ graph->disconnect(output);
+}
+
+void ConstantFolder::bypass_or_discard(ShaderInput *input) const
+{
+ 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;
+ }
+
+ 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;
+}
+
+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;
+}
+
+/* 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;
+ }
+}
+
+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;
+ 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;
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h
new file mode 100644
index 00000000000..2b31c2a5887
--- /dev/null
+++ b/intern/cycles/render/constant_fold.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONSTANT_FOLD_H__
+#define __CONSTANT_FOLD_H__
+
+#include "util_types.h"
+#include "svm_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class ShaderGraph;
+class ShaderInput;
+class ShaderNode;
+class ShaderOutput;
+
+class ConstantFolder {
+public:
+ ShaderGraph *const graph;
+ ShaderNode *const node;
+ ShaderOutput *const output;
+
+ ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output);
+
+ 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;
+
+ /* 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;
+
+ /* 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;
+
+ /* 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__ */
+
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
index 3d9b4e1f347..e41967eebf5 100644
--- a/intern/cycles/render/curves.h
+++ b/intern/cycles/render/curves.h
@@ -63,23 +63,23 @@ public:
ParticleCurveData();
~ParticleCurveData();
- vector<int> psys_firstcurve;
- vector<int> psys_curvenum;
- vector<int> psys_shader;
-
- vector<float> psys_rootradius;
- vector<float> psys_tipradius;
- vector<float> psys_shape;
- vector<bool> psys_closetip;
-
- vector<int> curve_firstkey;
- vector<int> curve_keynum;
- vector<float> curve_length;
- vector<float3> curve_uv;
- vector<float3> curve_vcol;
-
- vector<float3> curvekey_co;
- vector<float> curvekey_time;
+ 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<int> curve_firstkey;
+ array<int> curve_keynum;
+ array<float> curve_length;
+ array<float3> curve_uv;
+ array<float3> curve_vcol;
+
+ array<float3> curvekey_co;
+ array<float> curvekey_time;
};
/* HairSystem Manager */
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 12dce6ad999..e10a938e1eb 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -465,7 +465,7 @@ void Film::device_free(Device * /*device*/,
bool Film::modified(const Film& film)
{
- return Node::modified(film) || !Pass::equals(passes, film.passes);
+ return !Node::equals(film) || !Pass::equals(passes, film.passes);
}
void Film::tag_passes_update(Scene *scene, const array<Pass>& passes_)
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 24e4c9f33d5..3eeb7ffc2bc 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
#include "graph.h"
#include "nodes.h"
#include "shader.h"
+#include "constant_fold.h"
#include "util_algorithm.h"
#include "util_debug.h"
@@ -51,73 +52,19 @@ bool check_node_inputs_traversed(const ShaderNode *node,
return true;
}
-bool check_node_inputs_equals(const ShaderNode *node_a,
- const ShaderNode *node_b)
-{
- if(node_a->inputs.size() != node_b->inputs.size()) {
- /* Happens with BSDF closure nodes which are currently sharing the same
- * name for all the BSDF types, making it impossible to filter out
- * incompatible nodes.
- */
- return false;
- }
- for(int i = 0; i < node_a->inputs.size(); ++i) {
- ShaderInput *input_a = node_a->inputs[i],
- *input_b = node_b->inputs[i];
- if(input_a->link == NULL && input_b->link == NULL) {
- /* Unconnected inputs are expected to have the same value. */
- if(input_a->value != input_b->value) {
- 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;
-}
-
} /* namespace */
-/* Input and Output */
-
-ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
-{
- parent = parent_;
- name = name_;
- type = type_;
- link = NULL;
- value = make_float3(0.0f, 0.0f, 0.0f);
- stack_offset = SVM_STACK_INVALID;
- default_value = NONE;
- usage = USE_ALL;
-}
-
-ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
-{
- parent = parent_;
- name = name_;
- type = type_;
- stack_offset = SVM_STACK_INVALID;
-}
-
/* Node */
-ShaderNode::ShaderNode(const char *name_)
+ShaderNode::ShaderNode(const NodeType *type)
+: Node(type)
{
- name = name_;
+ name = type->name;
id = -1;
bump = SHADER_BUMP_NONE;
special_type = SHADER_SPECIAL_TYPE_NONE;
+
+ create_inputs_outputs(type);
}
ShaderNode::~ShaderNode()
@@ -129,10 +76,23 @@ ShaderNode::~ShaderNode()
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));
+ }
+}
+
ShaderInput *ShaderNode::input(const char *name)
{
foreach(ShaderInput *socket, inputs) {
- if(strcmp(socket->name, name) == 0)
+ if(socket->name() == name)
return socket;
}
@@ -142,56 +102,42 @@ ShaderInput *ShaderNode::input(const char *name)
ShaderOutput *ShaderNode::output(const char *name)
{
foreach(ShaderOutput *socket, outputs)
- if(strcmp(socket->name, name) == 0)
+ if(socket->name() == name)
return socket;
return NULL;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value, int usage)
+ShaderInput *ShaderNode::input(ustring name)
{
- ShaderInput *input = new ShaderInput(this, name, type);
- input->value.x = value;
- input->usage = usage;
- inputs.push_back(input);
- return input;
-}
+ foreach(ShaderInput *socket, inputs) {
+ if(socket->name() == name)
+ return socket;
+ }
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value, int usage)
-{
- ShaderInput *input = new ShaderInput(this, name, type);
- input->value = value;
- input->usage = usage;
- inputs.push_back(input);
- return input;
+ return NULL;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage)
+ShaderOutput *ShaderNode::output(ustring name)
{
- ShaderInput *input = add_input(name, type);
- input->default_value = value;
- input->usage = usage;
- return input;
-}
+ foreach(ShaderOutput *socket, outputs)
+ if(socket->name() == name)
+ return socket;
-ShaderOutput *ShaderNode::add_output(const char *name, ShaderSocketType type)
-{
- ShaderOutput *output = new ShaderOutput(this, name, type);
- outputs.push_back(output);
- return output;
+ return NULL;
}
void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
foreach(ShaderInput *input, inputs) {
if(!input->link) {
- if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
+ 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->default_value == ShaderInput::TEXTURE_UV) {
+ else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(shader->has_surface)
attributes->add(ATTR_STD_UV);
}
@@ -199,6 +145,49 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
}
}
+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;
+}
+
/* Graph */
ShaderGraph::ShaderGraph()
@@ -256,18 +245,18 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
return;
}
- if(from->type != to->type) {
+ if(from->type() != to->type()) {
/* for closures we can't do automatic conversion */
- if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) {
+ if(from->type() == SocketType::CLOSURE || to->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,
- to->parent->name.c_str(), to->name);
+ 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 = add(new ConvertNode(from->type, to->type, true));
+ ShaderNode *convert = add(new ConvertNode(from->type(), to->type(), true));
connect(from, convert->inputs[0]);
connect(convert->outputs[0], to);
@@ -279,6 +268,17 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
}
}
+void ShaderGraph::disconnect(ShaderOutput *from)
+{
+ assert(!finalized);
+
+ foreach(ShaderInput *sock, from->links) {
+ sock->link = NULL;
+ }
+
+ from->links.clear();
+}
+
void ShaderGraph::disconnect(ShaderInput *to)
{
assert(!finalized);
@@ -374,24 +374,12 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
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();
-
- foreach(ShaderInput *input, node->inputs) {
- ShaderInput *ninput = new ShaderInput(*input);
- nnode->inputs.push_back(ninput);
-
- ninput->parent = nnode;
- ninput->link = NULL;
- }
-
- foreach(ShaderOutput *output, node->outputs) {
- ShaderOutput *noutput = new ShaderOutput(*output);
- nnode->outputs.push_back(noutput);
-
- noutput->parent = nnode;
- noutput->links.clear();
- }
+ nnode->create_inputs_outputs(nnode->type);
}
/* recreate links */
@@ -401,8 +389,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
/* 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);
+ ShaderOutput *noutput = nfrom->output(input->link->name());
+ ShaderInput *ninput = nto->input(input->name());
/* connect */
connect(noutput, ninput);
@@ -447,10 +435,10 @@ void ShaderGraph::remove_proxy_nodes()
vector<ShaderInput*> links = tonode->outputs[0]->links;
foreach(ShaderInput *autoin, links) {
- if(autoin->default_value == ShaderInput::NONE)
- all_links_removed = false;
- else
+ if(autoin->flags() & SocketType::DEFAULT_LINK_MASK)
disconnect(autoin);
+ else
+ all_links_removed = false;
}
if(all_links_removed)
@@ -460,8 +448,7 @@ void ShaderGraph::remove_proxy_nodes()
disconnect(to);
/* transfer the default input value to the target socket */
- to->set(input->value);
- to->set(input->value_string);
+ tonode->copy_value(to->socket_type, *proxy, input->socket_type);
}
}
@@ -527,16 +514,8 @@ void ShaderGraph::constant_fold()
}
}
/* Optimize current node. */
- float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
- if(node->constant_fold(this, output, &optimized_value)) {
- /* Apply optimized value to connected sockets. */
- vector<ShaderInput*> links(output->links);
- foreach(ShaderInput *input, links) {
- /* Assign value and disconnect the optimizedinput. */
- input->value = optimized_value;
- disconnect(input);
- }
- }
+ ConstantFolder folder(this, node, output);
+ node->constant_fold(folder);
}
}
}
@@ -561,8 +540,8 @@ void ShaderGraph::deduplicate_nodes()
* already deduplicated.
*/
- ShaderNodeSet scheduled;
- map<ustring, ShaderNodeSet> done;
+ ShaderNodeSet scheduled, done;
+ map<ustring, ShaderNodeSet> candidates;
queue<ShaderNode*> traverse_queue;
/* Schedule nodes which doesn't have any dependencies. */
@@ -576,7 +555,7 @@ void ShaderGraph::deduplicate_nodes()
while(!traverse_queue.empty()) {
ShaderNode *node = traverse_queue.front();
traverse_queue.pop();
- done[node->name].insert(node);
+ done.insert(node);
/* Schedule the nodes which were depending on the current node. */
foreach(ShaderOutput *output, node->outputs) {
foreach(ShaderInput *input, output->links) {
@@ -587,35 +566,28 @@ void ShaderGraph::deduplicate_nodes()
continue;
}
/* Schedule node if its inputs are fully done. */
- if(check_node_inputs_traversed(input->parent, done[input->parent->name])) {
+ if(check_node_inputs_traversed(input->parent, done)) {
traverse_queue.push(input->parent);
scheduled.insert(input->parent);
}
}
}
/* Try to merge this node with another one. */
- foreach(ShaderNode *other_node, done[node->name]) {
- if(node == other_node) {
- /* Don't merge with self. */
- continue;
- }
- if(node->name != other_node->name) {
- /* Can only de-duplicate nodes of the same type. */
- continue;
- }
- if(!check_node_inputs_equals(node, other_node)) {
- /* Node inputs are different, can't merge them, */
- continue;
+ 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(!node->equals(other_node)) {
- /* Node settings are different. */
- continue;
- }
- /* TODO(sergey): Consider making it an utility function. */
+ }
+ /* 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], other_node->outputs[i]);
+ relink(node, node->outputs[i], merge_with->outputs[i]);
}
- break;
+ }
+ else {
+ candidates[node->type->name].insert(node);
}
}
}
@@ -706,38 +678,38 @@ void ShaderGraph::default_inputs(bool do_osl)
foreach(ShaderNode *node, nodes) {
foreach(ShaderInput *input, node->inputs) {
- if(!input->link && ((input->usage & ShaderInput::USE_SVM) || do_osl)) {
- if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
+ 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);
}
- else if(input->default_value == ShaderInput::TEXTURE_UV) {
+ else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(!texco)
texco = new TextureCoordinateNode();
connect(texco->output("UV"), input);
}
- else if(input->default_value == ShaderInput::INCOMING) {
+ else if(input->flags() & SocketType::LINK_INCOMING) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Incoming"), input);
}
- else if(input->default_value == ShaderInput::NORMAL) {
+ else if(input->flags() & SocketType::LINK_NORMAL) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Normal"), input);
}
- else if(input->default_value == ShaderInput::POSITION) {
+ else if(input->flags() & SocketType::LINK_POSITION) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Position"), input);
}
- else if(input->default_value == ShaderInput::TANGENT) {
+ else if(input->flags() & SocketType::LINK_TANGENT) {
if(!geom)
geom = new GeometryNode();
@@ -785,8 +757,8 @@ void ShaderGraph::refine_bump_nodes()
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);
+ 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"));
@@ -860,9 +832,9 @@ void ShaderGraph::bump_from_displacement()
ShaderNode *bump = add(new BumpNode());
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);
+ 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());
connect(out_center, bump->input("SampleCenter"));
connect(out_dx, bump->input("SampleX"));
@@ -882,7 +854,7 @@ void ShaderGraph::bump_from_displacement()
continue;
}
foreach(ShaderInput *input, node->inputs) {
- if(!input->link && input->default_value == ShaderInput::NORMAL)
+ if(!input->link && (input->flags() & SocketType::LINK_NORMAL))
connect(set_normal->output("Normal"), input);
}
}
@@ -918,14 +890,15 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(fin) {
/* mix closure: add node to mix closure weights */
- ShaderNode *mix_node = add(new MixClosureWeightNode());
+ 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
- fac_in->value = fin->value;
+ mix_node->fac = node->get_float(fin->socket_type);
if(weight_out)
connect(weight_out, weight_in);
@@ -952,20 +925,20 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
return;
/* already has a weight connected to it? add weights */
- if(weight_in->link || weight_in->value.x != 0.0f) {
- ShaderNode *math_node = add(new MathNode());
- ShaderInput *value1_in = math_node->input("Value1");
- ShaderInput *value2_in = math_node->input("Value2");
+ 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, value1_in);
+ connect(weight_in->link, math_node->input("Value1"));
else
- value1_in->value = weight_in->value;
+ math_node->value1 = weight_value;
if(weight_out)
- connect(weight_out, value2_in);
+ connect(weight_out, math_node->input("Value2"));
else
- value2_in->value.x = 1.0f;
+ math_node->value2 = 1.0f;
weight_out = math_node->output("Value");
if(weight_in->link)
@@ -976,7 +949,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(weight_out)
connect(weight_out, weight_in);
else
- weight_in->value.x += 1.0f;
+ node->set(weight_in->socket_type, weight_value + 1.0f);
}
}
@@ -994,6 +967,9 @@ int ShaderGraph::get_num_closures()
else if(CLOSURE_IS_GLASS(closure_type)) {
num_closures += 2;
}
+ else if(CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) {
+ num_closures += 2;
+ }
else {
++num_closures;
}
@@ -1024,7 +1000,7 @@ void ShaderGraph::dump_graph(const char *filename)
if(socket != node->inputs[0]) {
fprintf(fd, "|");
}
- fprintf(fd, "<IN_%p>%s", socket, socket->name);
+ fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str());
}
fprintf(fd, "}|");
}
@@ -1044,7 +1020,7 @@ void ShaderGraph::dump_graph(const char *filename)
if(socket != node->outputs[0]) {
fprintf(fd, "|");
}
- fprintf(fd, "<OUT_%p>%s", socket, socket->name);
+ fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str());
}
fprintf(fd, "}");
}
@@ -1058,7 +1034,7 @@ void ShaderGraph::dump_graph(const char *filename)
"// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
output,
input,
- output->name, input->name);
+ output->name().c_str(), input->name().c_str());
fprintf(fd,
"\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
output->parent,
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index bd3f5ca689a..b35be48d8ca 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,9 @@
#ifndef __GRAPH_H__
#define __GRAPH_H__
+#include "node.h"
+#include "node_type.h"
+
#include "kernel_types.h"
#include "util_list.h"
@@ -38,23 +41,7 @@ class ShaderGraph;
class SVMCompiler;
class OSLCompiler;
class OutputNode;
-
-/* Socket Type
- *
- * Data type for inputs and outputs */
-
-enum ShaderSocketType {
- SHADER_SOCKET_UNDEFINED,
-
- SHADER_SOCKET_FLOAT,
- SHADER_SOCKET_INT,
- SHADER_SOCKET_COLOR,
- SHADER_SOCKET_VECTOR,
- SHADER_SOCKET_POINT,
- SHADER_SOCKET_NORMAL,
- SHADER_SOCKET_CLOSURE,
- SHADER_SOCKET_STRING
-};
+class ConstantFolder;
/* Bump
*
@@ -86,30 +73,6 @@ enum ShaderNodeSpecialType {
SHADER_SPECIAL_TYPE_BUMP,
};
-/* Enum
- *
- * Utility class for enum values. */
-
-class ShaderEnum {
-public:
- bool empty() const { return left.empty(); }
- void insert(const char *x, int y) {
- left[ustring(x)] = y;
- right[y] = ustring(x);
- }
-
- bool exists(ustring x) { return left.find(x) != left.end(); }
- bool exists(int y) { return right.find(y) != right.end(); }
-
- int operator[](const char *x) { return left[ustring(x)]; }
- int operator[](ustring x) { return left[x]; }
- ustring operator[](int y) { return right[y]; }
-
-protected:
- map<ustring, int> left;
- map<int, ustring> right;
-};
-
/* Input
*
* Input socket for a shader node. May be linked to an output or not. If not
@@ -118,39 +81,21 @@ protected:
class ShaderInput {
public:
- enum DefaultValue {
- TEXTURE_GENERATED,
- TEXTURE_UV,
- INCOMING,
- NORMAL,
- POSITION,
- TANGENT,
- NONE
- };
-
- enum Usage {
- USE_SVM = 1,
- USE_OSL = 2,
- USE_ALL = USE_SVM|USE_OSL
- };
-
- ShaderInput(ShaderNode *parent, const char *name, ShaderSocketType type);
- void set(const float3& v) { value = v; }
- void set(float f) { value = make_float3(f, 0, 0); }
- void set(const ustring v) { value_string = v; }
-
- const char *name;
- ShaderSocketType type;
+ ShaderInput(const SocketType& socket_type_, ShaderNode* parent_)
+ : socket_type(socket_type_), parent(parent_), link(NULL), stack_offset(SVM_STACK_INVALID)
+ {}
- ShaderNode *parent;
- ShaderOutput *link;
+ ustring name() { return socket_type.ui_name; }
+ int flags() { return socket_type.flags; }
+ SocketType::Type type() { return socket_type.type; }
- DefaultValue default_value;
- float3 value;
- ustring value_string;
+ 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 */
- int usage;
};
/* Output
@@ -159,14 +104,16 @@ public:
class ShaderOutput {
public:
- ShaderOutput(ShaderNode *parent, const char *name, ShaderSocketType type);
+ ShaderOutput(const SocketType& socket_type_, ShaderNode* parent_)
+ : socket_type(socket_type_), parent(parent_), stack_offset(SVM_STACK_INVALID)
+ {}
- const char *name;
- ShaderNode *parent;
- ShaderSocketType type;
+ 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 */
};
@@ -175,18 +122,17 @@ public:
* Shader node in graph, with input and output sockets. This is the virtual
* base class for all node types. */
-class ShaderNode {
+class ShaderNode : public Node {
public:
- explicit ShaderNode(const char *name);
+ 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 *add_input(const char *name, ShaderSocketType type, float value=0.0f, int usage=ShaderInput::USE_ALL);
- ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value, int usage=ShaderInput::USE_ALL);
- ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage=ShaderInput::USE_ALL);
- ShaderOutput *add_output(const char *name, ShaderSocketType type);
+ ShaderInput *input(ustring name);
+ ShaderOutput *output(ustring name);
virtual ShaderNode *clone() const = 0;
virtual void attributes(Shader *shader, AttributeRequestSet *attributes);
@@ -195,7 +141,7 @@ public:
/* ** Node optimization ** */
/* Check whether the node can be replaced with single constant. */
- virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
+ 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.
@@ -213,7 +159,6 @@ public:
vector<ShaderInput*> inputs;
vector<ShaderOutput*> outputs;
- ustring name; /* name, not required to be unique */
int id; /* index in graph node array */
ShaderBump bump; /* for bump mapping utility */
@@ -249,23 +194,21 @@ public:
* 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)
- {
- return name == other->name &&
- bump == other->bump;
- }
+ 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); \
#define SHADER_NODE_NO_CLONE_CLASS(type) \
+ NODE_DECLARE; \
type(); \
virtual void compile(SVMCompiler& compiler); \
virtual void compile(OSLCompiler& compiler); \
@@ -307,6 +250,7 @@ public:
OutputNode *output();
void connect(ShaderOutput *from, ShaderInput *to);
+ void disconnect(ShaderOutput *from);
void disconnect(ShaderInput *to);
void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 6650c98aa38..614620c14af 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -36,59 +36,66 @@ ImageManager::ImageManager(const DeviceInfo& info)
osl_texture_system = NULL;
animation_frame = 0;
- /* Set image limits */
+ /* In case of multiple devices used we need to know type of an actual
+ * compute device.
+ *
+ * NOTE: We assume that all the devices are same type, otherwise we'll
+ * be screwed on so many levels..
+ */
+ DeviceType device_type = info.type;
+ if (device_type == DEVICE_MULTI) {
+ device_type = info.multi_devices[0].type;
+ }
- /* CPU */
- if(info.type == DEVICE_CPU) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CPU;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CPU;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_CPU;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_CPU;
+ /* Set image limits */
+#define SET_TEX_IMAGES_LIMITS(ARCH) \
+ { \
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_HALF4] = TEX_NUM_HALF4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_HALF] = TEX_NUM_HALF_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_HALF4] = TEX_START_HALF4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_HALF] = TEX_START_HALF_ ## ARCH; \
}
- /* CUDA (Fermi) */
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && !info.has_bindless_textures) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA;
+
+ if(device_type == DEVICE_CPU) {
+ SET_TEX_IMAGES_LIMITS(CPU);
}
- /* CUDA (Kepler and above) */
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.has_bindless_textures) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA_KEPLER;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA_KEPLER;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA_KEPLER;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA_KEPLER;
+ else if(device_type == DEVICE_CUDA) {
+ if(info.has_bindless_textures) {
+ SET_TEX_IMAGES_LIMITS(CUDA_KEPLER);
+ }
+ else {
+ SET_TEX_IMAGES_LIMITS(CUDA);
+ }
}
- /* OpenCL */
- else if(info.pack_images) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_OPENCL;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_OPENCL;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_OPENCL;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_OPENCL;
+ else if(device_type == DEVICE_OPENCL) {
+ SET_TEX_IMAGES_LIMITS(OPENCL);
}
- /* Should never happen */
else {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ /* Should not happen. */
tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0;
tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0;
tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0;
- tex_image_byte4_start = 0;
- tex_image_float_start = 0;
- tex_image_byte_start = 0;
+ tex_num_images[IMAGE_DATA_TYPE_HALF4] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_HALF] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_HALF4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_HALF] = 0;
assert(0);
}
+
+#undef SET_TEX_IMAGES_LIMITS
}
ImageManager::~ImageManager()
@@ -129,7 +136,7 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen
void *builtin_data,
bool& is_linear)
{
- bool is_float = false;
+ bool is_float = false, is_half = false;
is_linear = false;
int channels = 4;
@@ -168,6 +175,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen
}
}
+ /* check if it's half float */
+ if(spec.format == TypeDesc::HALF)
+ is_half = true;
+
channels = spec.nchannels;
/* basic color space detection, not great but better than nothing
@@ -193,7 +204,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen
delete in;
}
- if(is_float) {
+ if(is_half) {
+ return (channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
+ }
+ else if(is_float) {
return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
}
else {
@@ -207,34 +221,20 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen
* to device ones and vice versa. */
int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type)
{
- if(type == IMAGE_DATA_TYPE_BYTE4)
- return slot + tex_image_byte4_start;
- else if(type == IMAGE_DATA_TYPE_FLOAT)
- return slot + tex_image_float_start;
- else if(type == IMAGE_DATA_TYPE_BYTE)
- return slot + tex_image_byte_start;
- else
- return slot;
+ return slot + tex_start_images[type];
}
int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type)
{
- if(flat_slot >= tex_image_byte_start) {
- *type = IMAGE_DATA_TYPE_BYTE;
- return flat_slot - tex_image_byte_start;
- }
- else if(flat_slot >= tex_image_float_start) {
- *type = IMAGE_DATA_TYPE_FLOAT;
- return flat_slot - tex_image_float_start;
- }
- else if(flat_slot >= tex_image_byte4_start) {
- *type = IMAGE_DATA_TYPE_BYTE4;
- return flat_slot - tex_image_byte4_start;
- }
- else {
- *type = IMAGE_DATA_TYPE_FLOAT4;
- return flat_slot;
+ for(int i = IMAGE_DATA_NUM_TYPES - 1; i >= 0; i--) {
+ if(flat_slot >= tex_start_images[i]) {
+ *type = (ImageDataType)i;
+ return flat_slot - tex_start_images[i];
+ }
}
+
+ /* Should not happen. */
+ return flat_slot;
}
string ImageManager::name_from_type(int type)
@@ -245,6 +245,10 @@ string ImageManager::name_from_type(int type)
return "float";
else if(type == IMAGE_DATA_TYPE_BYTE)
return "byte";
+ else if(type == IMAGE_DATA_TYPE_HALF4)
+ return "half4";
+ else if(type == IMAGE_DATA_TYPE_HALF)
+ return "half";
else
return "byte4";
}
@@ -280,11 +284,16 @@ int ImageManager::add_image(const string& filename,
if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4)
is_float = true;
- /* No single channel textures on CUDA (Fermi) and OpenCL, use available slots */
- if(type == IMAGE_DATA_TYPE_FLOAT && tex_num_images[type] == 0)
+ /* No single channel and half textures on CUDA (Fermi) and OpenCL, use available slots */
+ if((type == IMAGE_DATA_TYPE_FLOAT ||
+ type == IMAGE_DATA_TYPE_HALF4 ||
+ type == IMAGE_DATA_TYPE_HALF) &&
+ tex_num_images[type] == 0) {
type = IMAGE_DATA_TYPE_FLOAT4;
- if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0)
+ }
+ if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) {
type = IMAGE_DATA_TYPE_BYTE4;
+ }
/* Fnd existing image. */
for(slot = 0; slot < images[type].size(); slot++) {
@@ -660,6 +669,107 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_
return true;
}
+template<typename T>
+bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
+{
+ ImageInput *in = NULL;
+ int width, height, depth, components;
+
+ if(!file_load_image_generic(img, &in, width, height, depth, components))
+ return false;
+
+ /* read RGBA pixels */
+ half *pixels = (half*)tex_img.resize(width, height, depth);
+ if(pixels == NULL) {
+ return false;
+ }
+
+ if(in) {
+ half *readpixels = pixels;
+ vector<half> tmppixels;
+
+ if(components > 4) {
+ tmppixels.resize(((size_t)width)*height*components);
+ readpixels = &tmppixels[0];
+ }
+
+ if(depth <= 1) {
+ int scanlinesize = width*components*sizeof(half);
+
+ in->read_image(TypeDesc::HALF,
+ (uchar*)readpixels + (height-1)*scanlinesize,
+ AutoStride,
+ -scanlinesize,
+ AutoStride);
+ }
+ else {
+ in->read_image(TypeDesc::HALF, (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();
+ }
+
+ in->close();
+ delete in;
+ }
+#if 0
+ /* TODO(dingto): Support half for ImBuf. */
+ else {
+ builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
+ }
+#endif
+
+ /* Check if we actually have a half4 slot, in case components == 1, but device
+ * doesn't support single channel textures. */
+ if(type == IMAGE_DATA_TYPE_HALF4) {
+ size_t num_pixels = ((size_t)width) * height * depth;
+ 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] = 1.0f;
+ 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] = 1.0f;
+ 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] = 1.0f;
+ }
+ }
+ }
+
+ return true;
+}
+
void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress)
{
if(progress->get_cancel())
@@ -759,7 +869,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
img->extension);
}
}
- else {
+ else if(type == IMAGE_DATA_TYPE_BYTE){
device_vector<uchar>& tex_img = dscene->tex_byte_image[slot];
if(tex_img.device_pointer) {
@@ -782,6 +892,55 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
img->extension);
}
}
+ else if(type == IMAGE_DATA_TYPE_HALF4){
+ device_vector<half4>& tex_img = dscene->tex_half4_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ if(!file_load_half_image(img, type, tex_img)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ half *pixels = (half*)tex_img.resize(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;
+ }
+
+ if(!pack_images) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension);
+ }
+ }
+ else if(type == IMAGE_DATA_TYPE_HALF){
+ device_vector<half>& tex_img = dscene->tex_half_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ if(!file_load_half_image(img, type, tex_img)) {
+ /* on failure to load, we set a 1x1 pixels pink image */
+ half *pixels = (half*)tex_img.resize(1, 1);
+
+ pixels[0] = TEX_IMAGE_MISSING_R;
+ }
+
+ if(!pack_images) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_alloc(name.c_str(),
+ tex_img,
+ img->interpolation,
+ img->extension);
+ }
+ }
img->need_load = false;
}
@@ -827,7 +986,7 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD
tex_img.clear();
}
- else {
+ else if(type == IMAGE_DATA_TYPE_BYTE){
device_vector<uchar>& tex_img = dscene->tex_byte_image[slot];
if(tex_img.device_pointer) {
@@ -837,6 +996,26 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD
tex_img.clear();
}
+ else if(type == IMAGE_DATA_TYPE_HALF4){
+ device_vector<half4>& tex_img = dscene->tex_half4_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ tex_img.clear();
+ }
+ else if(type == IMAGE_DATA_TYPE_HALF){
+ device_vector<half>& tex_img = dscene->tex_half_image[slot];
+
+ if(tex_img.device_pointer) {
+ thread_scoped_lock device_lock(device_mutex);
+ device->tex_free(tex_img);
+ }
+
+ tex_img.clear();
+ }
delete images[type][slot];
images[type][slot] = NULL;
@@ -897,6 +1076,26 @@ void ImageManager::device_update_slot(Device *device,
}
}
+uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot)
+{
+ uint8_t options = 0;
+
+ /* Image Options are packed into one uint:
+ * bit 0 -> Interpolation
+ * bit 1 + 2 + 3-> Extension */
+ if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST)
+ options |= (1 << 0);
+
+ if(images[type][slot]->extension == EXTENSION_REPEAT)
+ options |= (1 << 1);
+ else if(images[type][slot]->extension == EXTENSION_EXTEND)
+ options |= (1 << 2);
+ else /* EXTENSION_CLIP */
+ options |= (1 << 3);
+
+ return options;
+}
+
void ImageManager::device_pack_images(Device *device,
DeviceScene *dscene,
Progress& /*progess*/)
@@ -928,11 +1127,9 @@ void ImageManager::device_pack_images(Device *device,
device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot];
- /* The image options are packed
- bit 0 -> periodic
- bit 1 + 2 -> interpolation type */
- uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1;
- info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
+ uint8_t options = pack_image_options(type, slot);
+
+ info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
offset += tex_img.size();
@@ -960,11 +1157,8 @@ void ImageManager::device_pack_images(Device *device,
/* todo: support 3D textures, only CPU for now */
- /* The image options are packed
- bit 0 -> periodic
- bit 1 + 2 -> interpolation type */
- uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1;
- info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation);
+ uint8_t options = pack_image_options(type, slot);
+ info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options);
memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size());
offset += tex_img.size();
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 2ab16dd8967..07998684b23 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -41,6 +41,8 @@ public:
IMAGE_DATA_TYPE_BYTE4 = 1,
IMAGE_DATA_TYPE_FLOAT = 2,
IMAGE_DATA_TYPE_BYTE = 3,
+ IMAGE_DATA_TYPE_HALF4 = 4,
+ IMAGE_DATA_TYPE_HALF = 5,
IMAGE_DATA_NUM_TYPES
};
@@ -96,9 +98,8 @@ public:
private:
int tex_num_images[IMAGE_DATA_NUM_TYPES];
- int tex_image_byte4_start;
- int tex_image_float_start;
- int tex_image_byte_start;
+ int tex_start_images[IMAGE_DATA_NUM_TYPES];
+
thread_mutex device_mutex;
int animation_frame;
@@ -114,10 +115,15 @@ private:
template<typename T>
bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
+ template<typename T>
+ bool file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
+
int type_index_to_flattened_slot(int slot, ImageDataType type);
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type);
string name_from_type(int type);
+ uint8_t pack_image_options(ImageDataType type, size_t slot);
+
void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess);
void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot);
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 41e2571dc24..63914e57319 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -176,7 +176,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
max_samples = max(max_samples, volume_samples);
}
- max_samples *= (max_bounce + transparent_max_bounce + 3);
+ max_samples *= (max_bounce + transparent_max_bounce + 3 + BSSRDF_MAX_HITS);
int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM;
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
@@ -204,6 +204,11 @@ void Integrator::device_free(Device *device, DeviceScene *dscene)
dscene->sobol_directions.clear();
}
+bool Integrator::modified(const Integrator& integrator)
+{
+ return !Node::equals(integrator);
+}
+
void Integrator::tag_update(Scene *scene)
{
foreach(Shader *shader, scene->shaders) {
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index a5cfb0c7863..39eaaf246d4 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -86,6 +86,7 @@ public:
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);
};
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index c20bf6b5e9e..ae6042cef34 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -209,6 +209,29 @@ void LightManager::disable_ineffective_light(Device *device, Scene *scene)
}
}
+bool LightManager::object_usable_as_light(Object *object) {
+ Mesh *mesh = object->mesh;
+ /* Skip if we are not visible for BSDFs. */
+ if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
+ return false;
+ }
+ /* Skip motion blurred deforming meshes, not supported yet. */
+ if(mesh->has_motion_blur()) {
+ 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 *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
progress.set_status("Updating Lights", "Computing distribution");
@@ -226,39 +249,28 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
}
foreach(Object *object, scene->objects) {
- Mesh *mesh = object->mesh;
- bool have_emission = false;
-
- /* skip if we are not visible for BSDFs */
- if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT)))
- continue;
+ if(progress.get_cancel()) return;
- /* skip motion blurred deforming meshes, not supported yet */
- if(mesh->has_motion_blur())
+ if(!object_usable_as_light(object)) {
continue;
-
- /* skip if we have no emission shaders */
- foreach(Shader *shader, mesh->used_shaders) {
- if(shader->use_mis && shader->has_surface_emission) {
- have_emission = true;
- break;
- }
}
+ /* 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;
- /* count triangles */
- if(have_emission) {
- for(size_t i = 0; i < mesh->triangles.size(); 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++;
+ 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 */
float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
@@ -269,86 +281,68 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
int j = 0;
foreach(Object *object, scene->objects) {
- Mesh *mesh = object->mesh;
- bool have_emission = false;
+ if(progress.get_cancel()) return;
- /* skip if we are not visible for BSDFs */
- if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
+ 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;
- /* skip motion blurred deforming meshes, not supported yet */
- if(mesh->has_motion_blur()) {
- j++;
- continue;
- }
+ if(transform_applied)
+ object_id = ~object_id;
- /* skip if we have no emission shaders */
- foreach(Shader *shader, mesh->used_shaders) {
- if(shader->use_mis && shader->has_surface_emission) {
- have_emission = true;
- break;
- }
+ 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;
}
- /* sum area */
- if(have_emission) {
- bool transform_applied = mesh->transform_applied;
- Transform tfm = object->tfm;
- int object_id = j;
- int shader_flag = 0;
-
- if(transform_applied)
- object_id = ~object_id;
-
- 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;
- for(size_t i = 0; i < mesh->triangles.size(); 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].x = totarea;
- distribution[offset].y = __int_as_float(i + mesh->tri_offset);
- distribution[offset].z = __int_as_float(shader_flag);
- distribution[offset].w = __int_as_float(object_id);
- offset++;
-
- Mesh::Triangle t = mesh->triangles[i];
- 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);
+ if(shader->use_mis && shader->has_surface_emission) {
+ distribution[offset].x = totarea;
+ distribution[offset].y = __int_as_float(i + mesh->tri_offset);
+ distribution[offset].z = __int_as_float(shader_flag);
+ distribution[offset].w = __int_as_float(object_id);
+ offset++;
+
+ Mesh::Triangle t = mesh->get_triangle(i);
+ 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);
}
}
- if(progress.get_cancel()) return;
-
j++;
}
@@ -441,9 +435,9 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
device->tex_alloc("__light_distribution", dscene->light_distribution);
/* Portals */
- if(num_background_lights > 0 && light_index != scene->lights.size()) {
+ if(num_background_lights > 0 && light_index != num_lights) {
kintegrator->portal_offset = light_index;
- kintegrator->num_portals = scene->lights.size() - light_index;
+ kintegrator->num_portals = num_lights - light_index;
kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
}
else {
@@ -607,10 +601,21 @@ void LightManager::device_update_points(Device *device,
Scene *scene)
{
int num_scene_lights = scene->lights.size();
- if(num_scene_lights == 0)
+ int num_lights = 0;
+
+ foreach(Light *light, scene->lights) {
+ if(light->is_enabled) {
+ num_lights++;
+ }
+ }
+
+ float4 *light_data = dscene->light_data.resize(num_lights*LIGHT_SIZE);
+
+ if(num_lights == 0) {
+ VLOG(1) << "No effective light, ignoring points update.";
return;
+ }
- float4 *light_data = dscene->light_data.resize(num_scene_lights*LIGHT_SIZE);
int light_index = 0;
foreach(Light *light, scene->lights) {
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 2f1df1c9417..745caa96159 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
+class Object;
class Progress;
class Scene;
class Shader;
@@ -108,6 +109,9 @@ protected:
DeviceScene *dscene,
Scene *scene,
Progress& progress);
+
+ /* Check whether light manager can use the object as a light-emissive. */
+ bool object_usable_as_light(Object *object);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index d26404035eb..4cf0a785897 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -35,9 +35,6 @@
#include "util_progress.h"
#include "util_set.h"
-#include "subd_split.h"
-#include "subd_patch.h"
-
CCL_NAMESPACE_BEGIN
/* Triangle */
@@ -51,14 +48,45 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const
/* Curve */
-void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, 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];
+
+ 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;
+
+ 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]);
+
+ 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
{
float3 P[4];
- P[0] = float4_to_float3(curve_keys[max(first_key + k - 1,first_key)]);
- P[1] = float4_to_float3(curve_keys[first_key + k]);
- P[2] = float4_to_float3(curve_keys[first_key + k + 1]);
- P[3] = float4_to_float3(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]);
float3 lower;
float3 upper;
@@ -67,27 +95,62 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b
curvebounds(&lower.y, &upper.y, P, 1);
curvebounds(&lower.z, &upper.z, P, 2);
- float mr = max(curve_keys[first_key + k].w, curve_keys[first_key + k + 1].w);
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
bounds.grow(lower, mr);
bounds.grow(upper, mr);
}
+/* 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]];
+
+ return safe_normalize(cross(v1 - v0, v2 - v0));
+}
+
+
/* Mesh */
+NODE_DEFINE(Mesh)
+{
+ NodeType* type = NodeType::add("mesh", create);
+
+ 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);
+
+ 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_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;
+}
+
Mesh::Mesh()
+: Node(node_type)
{
need_update = true;
need_update_rebuild = false;
transform_applied = false;
transform_negative_scaled = false;
transform_normal = transform_identity();
- displacement_method = DISPLACE_BUMP;
bounds = BoundBox::empty;
- motion_steps = 3;
- use_motion_blur = false;
-
bvh = NULL;
tri_offset = 0;
@@ -96,11 +159,24 @@ Mesh::Mesh()
curve_offset = 0;
curvekey_offset = 0;
+ patch_offset = 0;
+ face_offset = 0;
+ corner_offset = 0;
+
+ num_subd_verts = 0;
+
attributes.triangle_mesh = this;
curve_attributes.curve_mesh = this;
+ subd_attributes.subd_mesh = this;
+
+ geometry_flags = GEOMETRY_NONE;
has_volume = false;
has_surface_bssrdf = false;
+
+ num_ngons = 0;
+
+ subdivision_type = SUBDIVISION_NONE;
}
Mesh::~Mesh()
@@ -108,21 +184,73 @@ Mesh::~Mesh()
delete bvh;
}
-void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys)
+void Mesh::resize_mesh(int numverts, int numtris)
{
- /* reserve space to add verts and triangles later */
verts.resize(numverts);
- triangles.resize(numtris);
+ triangles.resize(numtris * 3);
shader.resize(numtris);
smooth.resize(numtris);
- forms_quad.resize(numtris);
+ if(subd_faces.size()) {
+ triangle_patch.resize(numtris);
+ vert_patch_uv.resize(numverts);
+ }
+
+ 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);
+
+ if(subd_faces.size()) {
+ triangle_patch.reserve(numtris);
+ vert_patch_uv.reserve(numverts);
+ }
+
+ 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_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_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_attributes.resize();
+}
- curve_keys.resize(numcurvekeys);
- curves.resize(numcurves);
+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_;
- attributes.reserve();
- curve_attributes.reserve();
+ subd_attributes.resize(true);
}
void Mesh::clear()
@@ -133,13 +261,22 @@ void Mesh::clear()
shader.clear();
smooth.clear();
- forms_quad.clear();
+ triangle_patch.clear();
+ vert_patch_uv.clear();
curve_keys.clear();
- curves.clear();
+ curve_radius.clear();
+ curve_first_key.clear();
+ curve_shader.clear();
+
+ subd_faces.clear();
+ subd_face_corners.clear();
+
+ num_subd_verts = 0;
attributes.clear();
curve_attributes.clear();
+ subd_attributes.clear();
used_shaders.clear();
transform_applied = false;
@@ -151,7 +288,7 @@ void Mesh::clear()
int Mesh::split_vertex(int vertex)
{
/* copy vertex location and vertex attributes */
- verts.push_back(verts[vertex]);
+ add_vertex_slow(verts[vertex]);
foreach(Attribute& attr, attributes.attributes) {
if(attr.element == ATTR_ELEMENT_VERTEX) {
@@ -161,51 +298,77 @@ int Mesh::split_vertex(int vertex)
}
}
+ foreach(Attribute& attr, subd_attributes.attributes) {
+ if(attr.element == ATTR_ELEMENT_VERTEX) {
+ vector<char> tmp(attr.data_sizeof());
+ memcpy(&tmp[0], attr.data() + tmp.size()*vertex, tmp.size());
+ attr.add(&tmp[0]);
+ }
+ }
+
return verts.size() - 1;
}
-void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
+void Mesh::add_vertex(float3 P)
+{
+ verts.push_back_reserved(P);
+
+ if(subd_faces.size()) {
+ vert_patch_uv.push_back_reserved(make_float2(0.0f, 0.0f));
+ }
+}
+
+void Mesh::add_vertex_slow(float3 P)
{
- Triangle tri;
- tri.v[0] = v0;
- tri.v[1] = v1;
- tri.v[2] = v2;
-
- triangles[i] = tri;
- shader[i] = shader_;
- smooth[i] = smooth_;
- forms_quad[i] = forms_quad_;
+ verts.push_back_slow(P);
+
+ 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_, bool forms_quad_)
+void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
{
- Triangle tri;
- tri.v[0] = v0;
- tri.v[1] = v1;
- tri.v[2] = v2;
-
- triangles.push_back(tri);
- shader.push_back(shader_);
- smooth.push_back(smooth_);
- forms_quad.push_back(forms_quad_);
+ 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);
+ }
}
void Mesh::add_curve_key(float3 co, float radius)
{
- float4 key = float3_to_float4(co);
- key.w = radius;
+ curve_keys.push_back_reserved(co);
+ curve_radius.push_back_reserved(radius);
+}
- curve_keys.push_back(key);
+void Mesh::add_curve(int first_key, int shader)
+{
+ curve_first_key.push_back_reserved(first_key);
+ curve_shader.push_back_reserved(shader);
}
-void Mesh::add_curve(int first_key, int num_keys, int shader)
+void Mesh::add_subd_face(int* corners, int num_corners, int shader_, bool smooth_)
{
- Curve curve;
- curve.first_key = first_key;
- curve.num_keys = num_keys;
- curve.shader = shader;
+ int start_corner = subd_face_corners.size();
+
+ for(int i = 0; i < num_corners; i++) {
+ subd_face_corners.push_back_reserved(corners[i]);
+ }
- curves.push_back(curve);
+ 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();
+ }
+
+ SubdFace face = {start_corner, num_corners, shader_, smooth_, ptex_offset};
+ subd_faces.push_back_reserved(face);
}
void Mesh::compute_bounds()
@@ -219,7 +382,7 @@ void Mesh::compute_bounds()
bnds.grow(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
- bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+ bnds.grow(curve_keys[i], curve_radius[i]);
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(use_motion_blur && attr) {
@@ -247,7 +410,7 @@ void Mesh::compute_bounds()
bnds.grow_safe(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
- bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+ bnds.grow_safe(curve_keys[i], curve_radius[i]);
if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
@@ -301,15 +464,14 @@ void Mesh::add_face_normals()
float3 *fN = attr_fN->data_float3();
/* compute face normals */
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
bool flip = transform_negative_scaled;
if(triangles_size) {
float3 *verts_ptr = &verts[0];
- Triangle *triangles_ptr = &triangles[0];
for(size_t i = 0; i < triangles_size; i++) {
- fN[i] = compute_face_normal(triangles_ptr[i], verts_ptr);
+ fN[i] = compute_face_normal(get_triangle(i), verts_ptr);
if(flip)
fN[i] = -fN[i];
@@ -329,7 +491,7 @@ void Mesh::add_vertex_normals()
{
bool flip = transform_negative_scaled;
size_t verts_size = verts.size();
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
/* static vertex normals */
if(!attributes.find(ATTR_STD_VERTEX_NORMAL)) {
@@ -344,11 +506,10 @@ void Mesh::add_vertex_normals()
memset(vN, 0, verts.size()*sizeof(float3));
if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
for(size_t i = 0; i < triangles_size; i++)
for(size_t j = 0; j < 3; j++)
- vN[triangles_ptr[i].v[j]] += fN[i];
+ vN[get_triangle(i).v[j]] += fN[i];
}
for(size_t i = 0; i < verts_size; i++) {
@@ -374,12 +535,10 @@ void Mesh::add_vertex_normals()
memset(mN, 0, verts.size()*sizeof(float3));
if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
for(size_t i = 0; i < triangles_size; i++) {
for(size_t j = 0; j < 3; j++) {
- float3 fN = compute_face_normal(triangles_ptr[i], mP);
- mN[triangles_ptr[i].v[j]] += fN;
+ float3 fN = compute_face_normal(get_triangle(i), mP);
+ mN[get_triangle(i).v[j]] += fN;
}
}
}
@@ -402,8 +561,8 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
uint last_shader = -1;
bool last_smooth = false;
- size_t triangles_size = triangles.size();
- uint *shader_ptr = (shader.size())? &shader[0]: NULL;
+ size_t triangles_size = num_triangles();
+ int *shader_ptr = (shader.size())? &shader[0]: NULL;
bool do_transform = transform_applied;
Transform ntfm = transform_normal;
@@ -433,32 +592,34 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
}
}
-void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
+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();
- if(verts_size) {
- float3 *verts_ptr = &verts[0];
+ if(verts_size && subd_faces.size()) {
+ float2 *vert_patch_uv_ptr = &vert_patch_uv[0];
for(size_t i = 0; i < verts_size; i++) {
- float3 p = verts_ptr[i];
- tri_verts[i] = make_float4(p.x, p.y, p.z, 0.0f);
+ tri_patch_uv[i] = vert_patch_uv_ptr[i];
}
}
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
for(size_t i = 0; i < triangles_size; i++) {
- Triangle t = triangles_ptr[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_vindex[i] = make_float4(
- __int_as_float(t.v[0] + vert_offset),
- __int_as_float(t.v[1] + vert_offset),
- __int_as_float(t.v[2] + vert_offset),
- 0);
+ tri_patch[i] = (!subd_faces.size()) ? -1 : (triangle_patch[i]*8 + patch_offset);
}
}
}
@@ -466,27 +627,25 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_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();
- float4 *keys_ptr = NULL;
/* pack curve keys */
if(curve_keys_size) {
- keys_ptr = &curve_keys[0];
+ float3 *keys_ptr = &curve_keys[0];
+ float *radius_ptr = &curve_radius[0];
for(size_t i = 0; i < curve_keys_size; i++)
- curve_key_co[i] = keys_ptr[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 = curves.size();
+ size_t curve_num = num_curves();
if(curve_num) {
- Curve *curve_ptr = &curves[0];
- int shader_id = 0;
-
for(size_t i = 0; i < curve_num; i++) {
- Curve curve = curve_ptr[i];
- Shader *shader = (curve.shader < used_shaders.size()) ?
- used_shaders[curve.shader] : scene->default_surface;
+ 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, this, false);
curve_data[i] = make_float4(
@@ -498,7 +657,60 @@ void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, s
}
}
-void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total)
+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;
+
+ if(num_faces) {
+ 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(DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total)
{
if(progress->get_cancel())
return;
@@ -529,6 +741,8 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
BVHParams bparams;
bparams.use_spatial_split = params->use_bvh_spatial_split;
bparams.use_qbvh = params->use_qbvh;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ params->use_bvh_unaligned_nodes;
delete bvh;
bvh = BVH::create(bparams, objects);
@@ -621,8 +835,9 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
osl_attr.value = attr;
osl_attr.offset = 0;
- og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr;
+ 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 */
@@ -652,11 +867,11 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
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][stdname] = osl_attr;
+ 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][req.name] = osl_attr;
+ og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr;
}
}
@@ -681,6 +896,28 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr;
}
}
+
+ if(req.subd_element != ATTR_ELEMENT_NONE) {
+ osl_attr.elem = req.subd_element;
+ osl_attr.offset = req.subd_offset;
+
+ 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
@@ -732,7 +969,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
else
id = scene->shader_manager->get_attribute_id(req.std);
- if(mesh->triangles.size()) {
+ if(mesh->num_triangles()) {
attr_map[index].x = id;
attr_map[index].y = req.triangle_element;
attr_map[index].z = as_uint(req.triangle_offset);
@@ -747,7 +984,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
index++;
- if(mesh->curves.size()) {
+ if(mesh->num_curves()) {
attr_map[index].x = id;
attr_map[index].y = req.curve_element;
attr_map[index].z = as_uint(req.curve_offset);
@@ -761,22 +998,32 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
}
index++;
- }
- /* terminator */
- attr_map[index].x = ATTR_STD_NONE;
- attr_map[index].y = 0;
- attr_map[index].z = 0;
- attr_map[index].w = 0;
+ if(mesh->subd_faces.size()) {
+ attr_map[index].x = id;
+ attr_map[index].y = req.subd_element;
+ attr_map[index].z = as_uint(req.subd_offset);
- index++;
+ 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
+ attr_map[index].w = NODE_ATTR_FLOAT3;
+ }
- attr_map[index].x = ATTR_STD_NONE;
- attr_map[index].y = 0;
- attr_map[index].z = 0;
- attr_map[index].w = 0;
+ index++;
+ }
+
+ /* terminator */
+ for(int i = 0; i < ATTR_PRIM_TYPES; i++) {
+ attr_map[index].x = ATTR_STD_NONE;
+ attr_map[index].y = 0;
+ attr_map[index].z = 0;
+ attr_map[index].w = 0;
- index++;
+ index++;
+ }
}
/* copy to device */
@@ -786,17 +1033,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
static void update_attribute_element_size(Mesh *mesh,
Attribute *mattr,
+ AttributePrimitive prim,
size_t *attr_float_size,
size_t *attr_float3_size,
size_t *attr_uchar4_size)
{
if(mattr) {
- size_t size = mattr->element_size(
- mesh->verts.size(),
- mesh->triangles.size(),
- mesh->motion_steps,
- mesh->curves.size(),
- mesh->curve_keys.size());
+ size_t size = mattr->element_size(mesh, prim);
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* pass */
@@ -824,6 +1067,7 @@ static void update_attribute_element_offset(Mesh *mesh,
vector<uchar4>& attr_uchar4,
size_t& attr_uchar4_offset,
Attribute *mattr,
+ AttributePrimitive prim,
TypeDesc& type,
int& offset,
AttributeElement& element)
@@ -834,12 +1078,7 @@ static void update_attribute_element_offset(Mesh *mesh,
type = mattr->type;
/* store attribute data in arrays */
- size_t size = mattr->element_size(
- mesh->verts.size(),
- mesh->triangles.size(),
- mesh->motion_steps,
- mesh->curves.size(),
- mesh->curve_keys.size());
+ size_t size = mattr->element_size(mesh, prim);
if(mattr->element == ATTR_ELEMENT_VOXEL) {
/* store slot in offset value */
@@ -893,10 +1132,18 @@ static void update_attribute_element_offset(Mesh *mesh,
offset -= mesh->vert_offset;
else if(element == ATTR_ELEMENT_VERTEX_MOTION)
offset -= mesh->vert_offset;
- else if(element == ATTR_ELEMENT_FACE)
- offset -= mesh->tri_offset;
- else if(element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE)
- offset -= 3*mesh->tri_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)
@@ -946,23 +1193,23 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
foreach(AttributeRequest& req, attributes.requests) {
Attribute *triangle_mattr = mesh->attributes.find(req);
Attribute *curve_mattr = mesh->curve_attributes.find(req);
-
- /* todo: get rid of this exception, it's only here for giving some
- * working texture coordinate for subdivision as we can't preserve
- * any attributes yet */
- if(!triangle_mattr && req.std == ATTR_STD_GENERATED) {
- triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED);
- if(mesh->verts.size())
- memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size());
- }
+ Attribute *subd_mattr = mesh->subd_attributes.find(req);
update_attribute_element_size(mesh,
triangle_mattr,
+ ATTR_PRIM_TRIANGLE,
&attr_float_size,
&attr_float3_size,
&attr_uchar4_size);
update_attribute_element_size(mesh,
curve_mattr,
+ ATTR_PRIM_CURVE,
+ &attr_float_size,
+ &attr_float3_size,
+ &attr_uchar4_size);
+ update_attribute_element_size(mesh,
+ subd_mattr,
+ ATTR_PRIM_SUBD,
&attr_float_size,
&attr_float3_size,
&attr_uchar4_size);
@@ -987,12 +1234,14 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
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,
attr_float, attr_float_offset,
attr_float3, attr_float3_offset,
attr_uchar4, attr_uchar4_offset,
triangle_mattr,
+ ATTR_PRIM_TRIANGLE,
req.triangle_type,
req.triangle_offset,
req.triangle_element);
@@ -1002,10 +1251,21 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
attr_float3, attr_float3_offset,
attr_uchar4, attr_uchar4_offset,
curve_mattr,
+ ATTR_PRIM_CURVE,
req.curve_type,
req.curve_offset,
req.curve_element);
+ update_attribute_element_offset(mesh,
+ attr_float, attr_float_offset,
+ attr_float3, attr_float3_offset,
+ attr_uchar4, attr_uchar4_offset,
+ subd_mattr,
+ ATTR_PRIM_SUBD,
+ req.subd_type,
+ req.subd_offset,
+ req.subd_element);
+
if(progress.get_cancel()) return;
}
}
@@ -1035,15 +1295,18 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
}
}
-void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void MeshManager::mesh_calc_offset(Scene *scene)
{
- /* count and update offsets */
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;
@@ -1051,26 +1314,97 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
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;
+ }
+ face_size += mesh->subd_faces.size();
+ corner_size += mesh->subd_face_corners.size();
+ }
+}
+
+void MeshManager::device_update_mesh(Device *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->triangles.size();
+ tri_size += mesh->num_triangles();
curve_key_size += mesh->curve_keys.size();
- curve_size += mesh->curves.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;
+ }
}
+ /* 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 {
+ PackedBVH& pack = bvh->pack;
+ for(size_t i = 0; i < pack.prim_index.size(); ++i) {
+ if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) {
+ tri_prim_index[pack.prim_index[i]] = pack.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.resize(tri_size);
float4 *vnormal = dscene->tri_vnormal.resize(vert_size);
- float4 *tri_verts = dscene->tri_verts.resize(vert_size);
- float4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
+ uint4 *tri_vindex = dscene->tri_vindex.resize(tri_size);
+ uint *tri_patch = dscene->tri_patch.resize(tri_size);
+ float2 *tri_patch_uv = dscene->tri_patch_uv.resize(vert_size);
foreach(Mesh *mesh, scene->meshes) {
- mesh->pack_normals(scene, &tri_shader[mesh->tri_offset], &vnormal[mesh->vert_offset]);
- mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset);
-
+ mesh->pack_normals(scene,
+ &tri_shader[mesh->tri_offset],
+ &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;
}
@@ -1079,8 +1413,9 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__tri_shader", dscene->tri_shader);
device->tex_alloc("__tri_vnormal", dscene->tri_vnormal);
- device->tex_alloc("__tri_verts", dscene->tri_verts);
device->tex_alloc("__tri_vindex", dscene->tri_vindex);
+ device->tex_alloc("__tri_patch", dscene->tri_patch);
+ device->tex_alloc("__tri_patch_uv", dscene->tri_patch_uv);
}
if(curve_size != 0) {
@@ -1097,6 +1432,33 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
device->tex_alloc("__curve_keys", dscene->curve_keys);
device->tex_alloc("__curves", dscene->curves);
}
+
+ if(patch_size != 0) {
+ progress.set_status("Updating Mesh", "Copying Patches to device");
+
+ uint *patch_data = dscene->patches.resize(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(progress.get_cancel()) return;
+ }
+
+ device->tex_alloc("__patches", dscene->patches);
+ }
+
+ if(for_displacement) {
+ float4 *prim_tri_verts = dscene->prim_tri_verts.resize(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]]);
+ }
+ }
+ device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts);
+ }
}
void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
@@ -1111,6 +1473,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.top_level = true;
bparams.use_qbvh = scene->params.use_qbvh;
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;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1135,9 +1499,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size());
device->tex_alloc("__object_node", dscene->object_node);
}
- if(pack.tri_storage.size()) {
- dscene->tri_storage.reference(&pack.tri_storage[0], pack.tri_storage.size());
- device->tex_alloc("__tri_storage", dscene->tri_storage);
+ if(pack.prim_tri_index.size()) {
+ dscene->prim_tri_index.reference((uint*)&pack.prim_tri_index[0], pack.prim_tri_index.size());
+ device->tex_alloc("__prim_tri_index", dscene->prim_tri_index);
+ }
+ if(pack.prim_tri_verts.size()) {
+ dscene->prim_tri_verts.reference((float4*)&pack.prim_tri_verts[0], pack.prim_tri_verts.size());
+ device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts);
}
if(pack.prim_type.size()) {
dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size());
@@ -1238,7 +1606,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
- /* update normals */
+ /* Update normals. */
foreach(Mesh *mesh, scene->meshes) {
foreach(Shader *shader, mesh->used_shaders) {
if(shader->need_update_attributes)
@@ -1254,17 +1622,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
/* Update images needed for true displacement. */
- bool need_displacement_images = false;
+ bool true_displacement_used = false;
bool old_need_object_flags_update = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->displacement_method != Mesh::DISPLACE_BUMP)
{
- need_displacement_images = true;
+ true_displacement_used = true;
break;
}
}
- if(need_displacement_images) {
+ if(true_displacement_used) {
VLOG(1) << "Updating images used for true displacement.";
device_update_displacement_images(device, dscene, scene, progress);
old_need_object_flags_update = scene->object_manager->need_flags_update;
@@ -1275,42 +1643,46 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
false);
}
- /* device update */
+ /* Device update. */
device_free(device, dscene);
- device_update_mesh(device, dscene, scene, progress);
+ 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 */
+ /* Update displacement. */
bool displacement_done = false;
-
- foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && displace(device, dscene, scene, mesh, progress))
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update &&
+ displace(device, dscene, scene, mesh, progress))
+ {
displacement_done = true;
+ }
+ }
- /* todo: properly handle cancel halfway displacement */
+ /* TODO: properly handle cancel halfway displacement */
if(progress.get_cancel()) return;
- /* device re-update after displacement */
+ /* Device re-update after displacement. */
if(displacement_done) {
device_free(device, dscene);
- device_update_mesh(device, dscene, scene, progress);
- if(progress.get_cancel()) return;
-
device_update_attributes(device, dscene, scene, progress);
if(progress.get_cancel()) return;
}
- /* update bvh */
+ /* Update bvh. */
size_t i = 0, num_bvh = 0;
-
- foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && mesh->need_build_bvh())
+ foreach(Mesh *mesh, scene->meshes) {
+ if(mesh->need_update && mesh->need_build_bvh()) {
num_bvh++;
+ }
+ }
TaskPool pool;
@@ -1318,6 +1690,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
if(mesh->need_update) {
pool.push(function_bind(&Mesh::compute_bvh,
mesh,
+ dscene,
&scene->params,
&progress,
i,
@@ -1333,8 +1706,9 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
VLOG(2) << "Objects BVH build pool statistics:\n"
<< summary.full_report();
- foreach(Shader *shader, scene->shaders)
+ foreach(Shader *shader, scene->shaders) {
shader->need_update_attributes = false;
+ }
#ifdef __OBJECT_MOTION__
Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading);
@@ -1343,18 +1717,23 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
bool motion_blur = false;
#endif
- /* update obejcts */
+ /* Update objects. */
vector<Object *> volume_objects;
- foreach(Object *object, scene->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(need_displacement_images) {
+ if(true_displacement_used) {
/* Re-tag flags for update, so they're re-evaluated
* for meshes with correct bounding boxes.
*
@@ -1370,7 +1749,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->bvh_leaf_nodes);
device->tex_free(dscene->object_node);
- device->tex_free(dscene->tri_storage);
+ device->tex_free(dscene->prim_tri_verts);
+ device->tex_free(dscene->prim_tri_index);
device->tex_free(dscene->prim_type);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index);
@@ -1378,9 +1758,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->tri_shader);
device->tex_free(dscene->tri_vnormal);
device->tex_free(dscene->tri_vindex);
- device->tex_free(dscene->tri_verts);
+ device->tex_free(dscene->tri_patch);
+ device->tex_free(dscene->tri_patch_uv);
device->tex_free(dscene->curves);
device->tex_free(dscene->curve_keys);
+ device->tex_free(dscene->patches);
device->tex_free(dscene->attributes_map);
device->tex_free(dscene->attributes_float);
device->tex_free(dscene->attributes_float3);
@@ -1388,7 +1770,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear();
dscene->object_node.clear();
- dscene->tri_storage.clear();
+ dscene->prim_tri_verts.clear();
+ dscene->prim_tri_index.clear();
dscene->prim_type.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear();
@@ -1396,9 +1779,11 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->tri_shader.clear();
dscene->tri_vnormal.clear();
dscene->tri_vindex.clear();
- dscene->tri_verts.clear();
+ dscene->tri_patch.clear();
+ dscene->tri_patch_uv.clear();
dscene->curves.clear();
dscene->curve_keys.clear();
+ dscene->patches.clear();
dscene->attributes_map.clear();
dscene->attributes_float.clear();
dscene->attributes_float3.clear();
@@ -1448,74 +1833,5 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name)
return false;
}
-void Mesh::tessellate(DiagSplit *split)
-{
- int num_faces = triangles.size();
-
- add_face_normals();
- add_vertex_normals();
-
- Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
- float3 *fN = attr_fN->data_float3();
-
- Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
- float3 *vN = attr_vN->data_float3();
-
- for(int f = 0; f < num_faces; f++) {
- if(!forms_quad[f]) {
- /* triangle */
- LinearTrianglePatch patch;
- float3 *hull = patch.hull;
- float3 *normals = patch.normals;
-
- for(int i = 0; i < 3; i++) {
- hull[i] = verts[triangles[f].v[i]];
- }
-
- if(smooth[f]) {
- for(int i = 0; i < 3; i++) {
- normals[i] = vN[triangles[f].v[i]];
- }
- }
- else {
- for(int i = 0; i < 3; i++) {
- normals[i] = fN[f];
- }
- }
-
- split->split_triangle(&patch);
- }
- else {
- /* quad */
- LinearQuadPatch patch;
- float3 *hull = patch.hull;
- float3 *normals = patch.normals;
-
- hull[0] = verts[triangles[f ].v[0]];
- hull[1] = verts[triangles[f ].v[1]];
- hull[3] = verts[triangles[f ].v[2]];
- hull[2] = verts[triangles[f+1].v[2]];
-
- if(smooth[f]) {
- normals[0] = vN[triangles[f ].v[0]];
- normals[1] = vN[triangles[f ].v[1]];
- normals[3] = vN[triangles[f ].v[2]];
- normals[2] = vN[triangles[f+1].v[2]];
- }
- else {
- for(int i = 0; i < 4; i++) {
- normals[i] = fN[f];
- }
- }
-
- split->split_quad(&patch);
-
- // consume second triangle in quad
- f++;
- }
-
- }
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 557b664bff3..c9ae9aab888 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -18,6 +18,7 @@
#define __MESH_H__
#include "attribute.h"
+#include "node.h"
#include "shader.h"
#include "util_boundbox.h"
@@ -42,8 +43,10 @@ class DiagSplit;
/* Mesh */
-class Mesh {
+class Mesh : public Node {
public:
+ NODE_DECLARE;
+
/* Mesh Triangle */
struct Triangle {
int v[3];
@@ -51,15 +54,60 @@ public:
void bounds_grow(const float3 *verts, BoundBox& bounds) 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;
- uint shader;
int num_segments() { return num_keys - 1; }
- void bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ BoundBox& bounds) const;
+ void bounds_grow(const int k,
+ const float3 *curve_keys,
+ const float *curve_radius,
+ const Transform& aligned_space,
+ BoundBox& bounds) 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; }
};
/* Displacement */
@@ -71,7 +119,13 @@ public:
DISPLACE_NUM_METHODS,
};
- ustring name;
+ enum SubdivisionType {
+ SUBDIVISION_NONE,
+ SUBDIVISION_LINEAR,
+ SUBDIVISION_CATMULL_CLARK,
+ };
+
+ SubdivisionType subdivision_type;
/* Mesh Data */
enum GeometryFlags {
@@ -82,21 +136,31 @@ public:
int geometry_flags; /* used to distinguish meshes with no verts
and meshed for which geometry is not created */
- vector<float3> verts;
- vector<Triangle> triangles;
- vector<uint> shader;
- vector<bool> smooth;
- vector<bool> forms_quad; /* used to tell if triangle is part of a quad patch */
+ 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;
bool has_volume; /* Set in the device_update_flags(). */
bool has_surface_bssrdf; /* Set in the device_update_flags(). */
- vector<float4> curve_keys; /* co + radius */
- vector<Curve> curves;
+ 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;
vector<Shader*> used_shaders;
AttributeSet attributes;
AttributeSet curve_attributes;
+ AttributeSet subd_attributes;
BoundBox bounds;
bool transform_applied;
@@ -119,16 +183,29 @@ public:
size_t curve_offset;
size_t curvekey_offset;
+ size_t patch_offset;
+ size_t face_offset;
+ size_t corner_offset;
+
+ size_t num_subd_verts;
+
/* Functions */
Mesh();
~Mesh();
- void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys);
+ 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();
- void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
- void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = 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 num_keys, int shader);
+ void add_curve(int first_key, int shader);
+ void add_subd_face(int* corners, int num_corners, int shader_, bool smooth_);
int split_vertex(int vertex);
void compute_bounds();
@@ -136,9 +213,20 @@ public:
void add_vertex_normals();
void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
- void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset);
+ 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 compute_bvh(SceneParams *params, Progress *progress, int n, int total);
+ void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset);
+
+ void compute_bvh(DeviceScene *dscene,
+ SceneParams *params,
+ Progress *progress,
+ int n,
+ int total);
bool need_attribute(Scene *scene, AttributeStandard std);
bool need_attribute(Scene *scene, ustring name);
@@ -182,15 +270,41 @@ public:
void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes);
void device_update(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, 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_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+
void device_free(Device *device, DeviceScene *dscene);
void tag_update(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_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_bvh(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+
+ void device_update_displacement_images(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
index d19bf2084d7..95f46ff02a2 100644
--- a/intern/cycles/render/mesh_displace.cpp
+++ b/intern/cycles/render/mesh_displace.cpp
@@ -60,8 +60,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
uint4 *d_input_data = d_input.resize(num_verts);
size_t d_input_size = 0;
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Mesh::Triangle t = mesh->triangles[i];
+ 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;
@@ -146,8 +147,8 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
float4 *offset = (float4*)d_output.data_pointer;
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Mesh::Triangle t = mesh->triangles[i];
+ 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;
diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp
new file mode 100644
index 00000000000..fe8e41e8d35
--- /dev/null
+++ b/intern/cycles/render/mesh_subdivision.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mesh.h"
+#include "attribute.h"
+
+#include "subd_split.h"
+#include "subd_patch.h"
+
+#include "util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+void Mesh::tessellate(DiagSplit *split)
+{
+ int num_faces = subd_faces.size();
+
+ 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];
+
+ if(face.is_quad()) {
+ /* quad */
+ LinearQuadPatch patch;
+ float3 *hull = patch.hull;
+ float3 *normals = patch.normals;
+
+ patch.patch_index = face.ptex_offset;
+ patch.shader = face.shader;
+
+ 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]);
+
+ /* 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.
+ */
+ QuadDice::SubPatch subpatch;
+ subpatch.patch = &patch;
+
+ 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(&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(&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(&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(&patch, &subpatch);
+ }
+ else {
+ /* ngon */
+ 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) {
+ 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;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index f75fef1c13e..cf366367873 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -19,8 +19,11 @@
#include "nodes.h"
#include "scene.h"
#include "svm.h"
+#include "svm_color_util.h"
+#include "svm_ramp_util.h"
#include "svm_math_util.h"
#include "osl.h"
+#include "constant_fold.h"
#include "util_sky_model.h"
#include "util_foreach.h"
@@ -30,64 +33,40 @@ CCL_NAMESPACE_BEGIN
/* Texture Mapping */
-static ShaderEnum texture_mapping_type_init()
-{
- ShaderEnum enm;
-
- enm.insert("Point", TextureMapping::POINT);
- enm.insert("Texture", TextureMapping::TEXTURE);
- enm.insert("Vector", TextureMapping::VECTOR);
- enm.insert("Normal", TextureMapping::NORMAL);
-
- return enm;
-}
-
-static ShaderEnum texture_mapping_mapping_init()
-{
- ShaderEnum enm;
-
- enm.insert("None", TextureMapping::NONE);
- enm.insert("X", TextureMapping::X);
- enm.insert("Y", TextureMapping::Y);
- enm.insert("Z", TextureMapping::Z);
-
- return enm;
-}
-
-static ShaderEnum texture_mapping_projection_init()
-{
- ShaderEnum enm;
-
- enm.insert("Flat", TextureMapping::FLAT);
- enm.insert("Cube", TextureMapping::CUBE);
- enm.insert("Tube", TextureMapping::TUBE);
- enm.insert("Sphere", TextureMapping::SPHERE);
-
- return enm;
-}
-
-ShaderEnum TextureMapping::type_enum = texture_mapping_type_init();
-ShaderEnum TextureMapping::mapping_enum = texture_mapping_mapping_init();
-ShaderEnum TextureMapping::projection_enum = texture_mapping_projection_init();
+#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);
TextureMapping::TextureMapping()
{
- translation = make_float3(0.0f, 0.0f, 0.0f);
- rotation = make_float3(0.0f, 0.0f, 0.0f);
- scale = make_float3(1.0f, 1.0f, 1.0f);
-
- min = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
- max = make_float3(FLT_MAX, FLT_MAX, FLT_MAX);
-
- use_minmax = false;
-
- x_mapping = X;
- y_mapping = Y;
- z_mapping = Z;
-
- type = TEXTURE;
-
- projection = FLAT;
}
Transform TextureMapping::compute_transform()
@@ -193,7 +172,7 @@ 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(SHADER_SOCKET_VECTOR);
+ int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
compile(compiler, offset_in, offset_out);
@@ -206,7 +185,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset)
{
if(!skip()) {
- compiler.stack_clear_offset(vector_in->type, vector_offset);
+ compiler.stack_clear_offset(vector_in->type(), vector_offset);
}
}
@@ -222,72 +201,66 @@ void TextureMapping::compile(OSLCompiler &compiler)
/* Image Texture */
-static ShaderEnum color_space_init()
+NODE_DEFINE(ImageTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER);
- enm.insert("None", 0);
- enm.insert("Color", 1);
+ TEXTURE_MAPPING_DEFINE(ImageTextureNode);
- return enm;
-}
+ SOCKET_STRING(filename, "Filename", ustring(""));
-static ShaderEnum image_projection_init()
-{
- ShaderEnum enm;
+ 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);
- enm.insert("Flat", NODE_IMAGE_PROJ_FLAT);
- enm.insert("Box", NODE_IMAGE_PROJ_BOX);
- enm.insert("Sphere", NODE_IMAGE_PROJ_SPHERE);
- enm.insert("Tube", NODE_IMAGE_PROJ_TUBE);
+ SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
- return enm;
-}
+ 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 const char* get_osl_interpolation_parameter(InterpolationType interpolation)
-{
- switch(interpolation) {
- case INTERPOLATION_CLOSEST:
- return "closest";
- case INTERPOLATION_CUBIC:
- return "cubic";
- case INTERPOLATION_SMART:
- return "smart";
- case INTERPOLATION_LINEAR:
- default:
- return "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 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);
-ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
-ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
+ 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");
+
+ return type;
+}
ImageTextureNode::ImageTextureNode()
-: ImageSlotTextureNode("image_texture")
+: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_linear = false;
- use_alpha = true;
- filename = "";
builtin_data = NULL;
- color_space = ustring("Color");
- projection = ustring("Flat");
- interpolation = INTERPOLATION_LINEAR;
- extension = EXTENSION_REPEAT;
- projection_blend = 0.0f;
animated = false;
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
}
ImageTextureNode::~ImageTextureNode()
{
if(image_manager) {
- image_manager->remove_image(filename,
+ image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
extension);
@@ -328,7 +301,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(is_float == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -341,10 +314,10 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
}
if(slot != -1) {
- int srgb = (is_linear || color_space != "Color")? 0: 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 != "Box") {
+ if(projection != NODE_IMAGE_PROJ_BOX) {
compiler.add_node(NODE_TEX_IMAGE,
slot,
compiler.encode_uchar4(
@@ -352,7 +325,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
- projection_enum[projection]);
+ projection);
}
else {
compiler.add_node(NODE_TEX_IMAGE_BOX,
@@ -390,13 +363,13 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
if(is_float == -1) {
if(builtin_data == NULL) {
ImageManager::ImageDataType type;
- type = image_manager->get_image_metadata(filename, NULL, is_linear);
+ type = image_manager->get_image_metadata(filename.string(), NULL, is_linear);
if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
is_float = 1;
}
else {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -410,7 +383,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
}
if(slot == -1) {
- compiler.parameter("filename", filename.c_str());
+ compiler.parameter(this, "filename");
}
else {
/* TODO(sergey): It's not so simple to pass custom attribute
@@ -421,71 +394,72 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
*/
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- if(is_linear || color_space != "Color")
- compiler.parameter("color_space", "Linear");
+ if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
+ compiler.parameter("color_space", "linear");
else
compiler.parameter("color_space", "sRGB");
- compiler.parameter("projection", projection);
- compiler.parameter("projection_blend", projection_blend);
+ 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("interpolation", get_osl_interpolation_parameter(interpolation));
-
- switch(extension) {
- case EXTENSION_EXTEND:
- compiler.parameter("wrap", "clamp");
- break;
- case EXTENSION_CLIP:
- compiler.parameter("wrap", "black");
- break;
- case EXTENSION_REPEAT:
- default:
- compiler.parameter("wrap", "periodic");
- break;
- }
+ compiler.parameter(this, "interpolation");
+ compiler.parameter(this, "extension");
compiler.add(this, "node_image_texture");
}
/* Environment Texture */
-static ShaderEnum env_projection_init()
+NODE_DEFINE(EnvironmentTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER);
- enm.insert("Equirectangular", 0);
- enm.insert("Mirror Ball", 1);
+ TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
- return enm;
-}
+ 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);
+
+ 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 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);
-ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
-ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
EnvironmentTextureNode::EnvironmentTextureNode()
-: ImageSlotTextureNode("environment_texture")
+: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_linear = false;
- use_alpha = true;
- filename = "";
builtin_data = NULL;
- color_space = ustring("Color");
- interpolation = INTERPOLATION_LINEAR;
- projection = ustring("Equirectangular");
animated = false;
-
- add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
}
EnvironmentTextureNode::~EnvironmentTextureNode()
{
if(image_manager) {
- image_manager->remove_image(filename,
+ image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_REPEAT);
@@ -524,7 +498,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
if(slot == -1) {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -537,7 +511,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
}
if(slot != -1) {
- int srgb = (is_linear || color_space != "Color")? 0: 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,
@@ -547,7 +521,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
- projection_enum[projection]);
+ projection);
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -577,13 +551,13 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
if(is_float == -1) {
if(builtin_data == NULL) {
ImageManager::ImageDataType type;
- type = image_manager->get_image_metadata(filename, NULL, is_linear);
+ type = image_manager->get_image_metadata(filename.string(), NULL, is_linear);
if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
is_float = 1;
}
else {
bool is_float_bool;
- slot = image_manager->add_image(filename,
+ slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
@@ -597,19 +571,18 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
}
if(slot == -1) {
- compiler.parameter("filename", filename.c_str());
+ compiler.parameter(this, "filename");
}
else {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- compiler.parameter("projection", projection);
- if(is_linear || color_space != "Color")
- compiler.parameter("color_space", "Linear");
+ 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("interpolation", get_osl_interpolation_parameter(interpolation));
-
+ compiler.parameter(this, "interpolation");
compiler.parameter("is_float", is_float);
compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.add(this, "node_environment_texture");
@@ -640,10 +613,10 @@ static float sky_perez_function(float lam[6], float theta, float 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
- */
+ * 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;
@@ -738,29 +711,31 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
arhosekskymodelstate_free(sky_state);
}
-static ShaderEnum sky_type_init()
+NODE_DEFINE(SkyTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER);
- enm.insert("Preetham", NODE_SKY_OLD);
- enm.insert("Hosek / Wilkie", NODE_SKY_NEW);
+ TEXTURE_MAPPING_DEFINE(SkyTextureNode);
- return enm;
-}
+ 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);
-ShaderEnum SkyTextureNode::type_enum = sky_type_init();
+ 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("sky_texture")
+: TextureNode(node_type)
{
- type = ustring("Hosek / Wilkie");
-
- sun_direction = make_float3(0.0f, 0.0f, 1.0f);
- turbidity = 2.2f;
- ground_albedo = 0.3f;
-
- add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
- add_output("Color", SHADER_SOCKET_COLOR);
}
void SkyTextureNode::compile(SVMCompiler& compiler)
@@ -769,18 +744,17 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
ShaderOutput *color_out = output("Color");
SunSky sunsky;
- if(type_enum[type] == NODE_SKY_OLD)
+ if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
- else if(type_enum[type] == NODE_SKY_NEW)
+ 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);
- int sky_model = type_enum[type];
compiler.stack_assign(color_out);
- compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model);
+ 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]));
@@ -798,15 +772,14 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
tex_mapping.compile(compiler);
SunSky sunsky;
-
- if(type_enum[type] == NODE_SKY_OLD)
+ if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
- else if(type_enum[type] == NODE_SKY_NEW)
+ else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
- compiler.parameter("sky_model", type);
+ 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));
@@ -818,31 +791,33 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
/* Gradient Texture */
-static ShaderEnum gradient_type_init()
+NODE_DEFINE(GradientTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER);
- enm.insert("Linear", NODE_BLEND_LINEAR);
- enm.insert("Quadratic", NODE_BLEND_QUADRATIC);
- enm.insert("Easing", NODE_BLEND_EASING);
- enm.insert("Diagonal", NODE_BLEND_DIAGONAL);
- enm.insert("Radial", NODE_BLEND_RADIAL);
- enm.insert("Quadratic Sphere", NODE_BLEND_QUADRATIC_SPHERE);
- enm.insert("Spherical", NODE_BLEND_SPHERICAL);
+ TEXTURE_MAPPING_DEFINE(GradientTextureNode);
- return enm;
-}
+ 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);
-ShaderEnum GradientTextureNode::type_enum = gradient_type_init();
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
GradientTextureNode::GradientTextureNode()
-: TextureNode("gradient_texture")
+: TextureNode(node_type)
{
- type = ustring("Linear");
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
}
void GradientTextureNode::compile(SVMCompiler& compiler)
@@ -855,7 +830,7 @@ void GradientTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_GRADIENT,
compiler.encode_uchar4(
- type_enum[type],
+ type,
vector_offset,
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(color_out)));
@@ -867,22 +842,32 @@ void GradientTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
+ compiler.parameter(this, "type");
compiler.add(this, "node_gradient_texture");
}
/* Noise Texture */
-NoiseTextureNode::NoiseTextureNode()
-: TextureNode("noise_texture")
+NODE_DEFINE(NoiseTextureNode)
{
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
+ NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER);
+
+ 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_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+NoiseTextureNode::NoiseTextureNode()
+: TextureNode(node_type)
+{
}
void NoiseTextureNode::compile(SVMCompiler& compiler)
@@ -906,9 +891,9 @@ void NoiseTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(distortion_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(detail),
+ __float_as_int(distortion));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -922,28 +907,29 @@ void NoiseTextureNode::compile(OSLCompiler& compiler)
/* Voronoi Texture */
-static ShaderEnum voronoi_coloring_init()
+NODE_DEFINE(VoronoiTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
- enm.insert("Intensity", NODE_VORONOI_INTENSITY);
- enm.insert("Cells", NODE_VORONOI_CELLS);
+ TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
- return enm;
-}
+ 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);
-ShaderEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init();
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
-VoronoiTextureNode::VoronoiTextureNode()
-: TextureNode("voronoi_texture")
-{
- coloring = ustring("Intensity");
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
+ return type;
+}
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+VoronoiTextureNode::VoronoiTextureNode()
+: TextureNode(node_type)
+{
}
void VoronoiTextureNode::compile(SVMCompiler& compiler)
@@ -956,13 +942,13 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler)
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_VORONOI,
- coloring_enum[coloring],
+ coloring,
compiler.encode_uchar4(
compiler.stack_assign_if_linked(scale_in),
vector_offset,
compiler.stack_assign(fac_out),
compiler.stack_assign(color_out)),
- __float_as_int(scale_in->value.x));
+ __float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -971,42 +957,43 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Coloring", coloring);
+ compiler.parameter(this, "coloring");
compiler.add(this, "node_voronoi_texture");
}
/* Musgrave Texture */
-static ShaderEnum musgrave_type_init()
+NODE_DEFINE(MusgraveTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
- enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
- enm.insert("fBM", NODE_MUSGRAVE_FBM);
- enm.insert("Hybrid Multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
- enm.insert("Ridged Multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
- enm.insert("Hetero Terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
+ TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
- return enm;
-}
+ 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);
-ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init();
+ 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);
-MusgraveTextureNode::MusgraveTextureNode()
-: TextureNode("musgrave_texture")
-{
- type = ustring("fBM");
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f);
+ return type;
+}
- add_output("Fac", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+MusgraveTextureNode::MusgraveTextureNode()
+: TextureNode(node_type)
+{
}
void MusgraveTextureNode::compile(SVMCompiler& compiler)
@@ -1025,7 +1012,7 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_MUSGRAVE,
compiler.encode_uchar4(
- type_enum[type],
+ type,
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
@@ -1037,12 +1024,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(gain_in),
compiler.stack_assign_if_linked(scale_in)));
- compiler.add_node(__float_as_int(dimension_in->value.x),
- __float_as_int(lacunarity_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(offset_in->value.x));
- compiler.add_node(__float_as_int(gain_in->value.x),
- __float_as_int(scale_in->value.x));
+ 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);
}
@@ -1051,50 +1038,43 @@ void MusgraveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
-
+ compiler.parameter(this, "type");
compiler.add(this, "node_musgrave_texture");
}
/* Wave Texture */
-static ShaderEnum wave_type_init()
+NODE_DEFINE(WaveTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER);
- enm.insert("Bands", NODE_WAVE_BANDS);
- enm.insert("Rings", NODE_WAVE_RINGS);
+ TEXTURE_MAPPING_DEFINE(WaveTextureNode);
- return enm;
-}
+ 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 ShaderEnum wave_profile_init()
-{
- ShaderEnum enm;
+ 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);
- enm.insert("Sine", NODE_WAVE_PROFILE_SIN);
- enm.insert("Saw", NODE_WAVE_PROFILE_SAW);
+ 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);
- return enm;
-}
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
-ShaderEnum WaveTextureNode::type_enum = wave_type_init();
-ShaderEnum WaveTextureNode::profile_enum = wave_profile_init();
+ return type;
+}
WaveTextureNode::WaveTextureNode()
-: TextureNode("wave_texture")
+: TextureNode(node_type)
{
- type = ustring("Bands");
- profile = ustring("Sine");
-
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Detail Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
}
void WaveTextureNode::compile(SVMCompiler& compiler)
@@ -1111,7 +1091,7 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_WAVE,
compiler.encode_uchar4(
- type_enum[type],
+ type,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(dscale_in)),
@@ -1120,13 +1100,13 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(detail_in),
compiler.stack_assign_if_linked(distortion_in)),
- profile_enum[profile]);
+ profile);
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(distortion_in->value.x),
- __float_as_int(dscale_in->value.x));
+ __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);
}
@@ -1135,25 +1115,35 @@ void WaveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
- compiler.parameter("Profile", profile);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "profile");
compiler.add(this, "node_wave_texture");
}
/* Magic Texture */
-MagicTextureNode::MagicTextureNode()
-: TextureNode("magic_texture")
+NODE_DEFINE(MagicTextureNode)
{
- depth = 2;
+ NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(MagicTextureNode);
+
+ SOCKET_INT(depth, "Depth", 2);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 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);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+MagicTextureNode::MagicTextureNode()
+: TextureNode(node_type)
+{
}
void MagicTextureNode::compile(SVMCompiler& compiler)
@@ -1176,8 +1166,8 @@ void MagicTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(distortion_in)));
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(distortion_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(distortion));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1186,22 +1176,32 @@ void MagicTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Depth", depth);
+ compiler.parameter(this, "depth");
compiler.add(this, "node_magic_texture");
}
/* Checker Texture */
-CheckerTextureNode::CheckerTextureNode()
-: TextureNode("checker_texture")
+NODE_DEFINE(CheckerTextureNode)
{
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
+ NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ 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_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+CheckerTextureNode::CheckerTextureNode()
+: TextureNode(node_type)
+{
}
void CheckerTextureNode::compile(SVMCompiler& compiler)
@@ -1225,7 +1225,7 @@ void CheckerTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
- __float_as_int(scale_in->value.x));
+ __float_as_int(scale));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1239,26 +1239,37 @@ void CheckerTextureNode::compile(OSLCompiler& compiler)
/* Brick Texture */
-BrickTextureNode::BrickTextureNode()
-: TextureNode("brick_texture")
+NODE_DEFINE(BrickTextureNode)
{
- offset = 0.5f;
- offset_frequency = 2;
- squash = 1.0f;
- squash_frequency = 2;
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_input("Mortar", SHADER_SOCKET_COLOR);
- add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
- add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f);
- add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f);
+ NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER);
+
+ 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_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(bias, "Bias", 0.0f);
+ SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
+ SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
+BrickTextureNode::BrickTextureNode()
+: TextureNode(node_type)
+{
}
void BrickTextureNode::compile(SVMCompiler& compiler)
@@ -1295,12 +1306,12 @@ void BrickTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
- __float_as_int(scale_in->value.x),
- __float_as_int(mortar_size_in->value.x),
- __float_as_int(bias_in->value.x));
+ __float_as_int(scale),
+ __float_as_int(mortar_size),
+ __float_as_int(bias));
- compiler.add_node(__float_as_int(brick_width_in->value.x),
- __float_as_int(row_height_in->value.x),
+ compiler.add_node(__float_as_int(brick_width),
+ __float_as_int(row_height),
__float_as_int(offset),
__float_as_int(squash));
@@ -1311,48 +1322,55 @@ void BrickTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Offset", offset);
- compiler.parameter("OffsetFrequency", offset_frequency);
- compiler.parameter("Squash", squash);
- compiler.parameter("SquashFrequency", squash_frequency);
+ 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 */
-static ShaderEnum point_density_space_init()
+NODE_DEFINE(PointDensityTextureNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER);
- enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT);
- enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD);
+ SOCKET_STRING(filename, "Filename", ustring(""));
- return enm;
-}
+ 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);
-ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init();
+ 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_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");
+
+ return type;
+}
PointDensityTextureNode::PointDensityTextureNode()
-: ShaderNode("point_density")
+: ShaderNode(node_type)
{
image_manager = NULL;
slot = -1;
- filename = "";
- space = ustring("Object");
builtin_data = NULL;
- interpolation = INTERPOLATION_LINEAR;
-
- tfm = transform_identity();
-
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
- add_output("Density", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
}
PointDensityTextureNode::~PointDensityTextureNode()
{
if(image_manager) {
- image_manager->remove_image(filename,
+ image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_CLIP);
@@ -1390,7 +1408,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
- slot = image_manager->add_image(filename, builtin_data,
+ slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
is_float, is_linear,
interpolation,
@@ -1405,8 +1423,8 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign_if_linked(density_out),
compiler.stack_assign_if_linked(color_out),
- space_enum[space]));
- if(space == "World") {
+ space));
+ if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
@@ -1442,7 +1460,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
- slot = image_manager->add_image(filename, builtin_data,
+ slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
is_float, is_linear,
interpolation,
@@ -1453,37 +1471,34 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
if(slot != -1) {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- if(space == "World") {
+ if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", transform_transpose(tfm));
compiler.parameter("use_mapping", 1);
}
- switch(interpolation) {
- case INTERPOLATION_CLOSEST:
- compiler.parameter("interpolation", "closest");
- break;
- case INTERPOLATION_CUBIC:
- compiler.parameter("interpolation", "cubic");
- break;
- case INTERPOLATION_LINEAR:
- default:
- compiler.parameter("interpolation", "linear");
- break;
- }
-
+ compiler.parameter(this, "interpolation");
compiler.add(this, "node_voxel_texture");
}
}
/* Normal */
-NormalNode::NormalNode()
-: ShaderNode("normal")
+NODE_DEFINE(NormalNode)
{
- direction = make_float3(0.0f, 0.0f, 1.0f);
+ NodeType* type = NodeType::add("normal", create, NodeType::SHADER);
+
+ 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));
- add_input("Normal", SHADER_SOCKET_NORMAL);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("Dot", SHADER_SOCKET_FLOAT);
+ SOCKET_OUT_NORMAL(normal, "Normal");
+ SOCKET_OUT_FLOAT(dot, "Dot");
+
+ return type;
+}
+
+NormalNode::NormalNode()
+: ShaderNode(node_type)
+{
}
void NormalNode::compile(SVMCompiler& compiler)
@@ -1504,17 +1519,27 @@ void NormalNode::compile(SVMCompiler& compiler)
void NormalNode::compile(OSLCompiler& compiler)
{
- compiler.parameter_normal("Direction", direction);
+ compiler.parameter(this, "direction");
compiler.add(this, "node_normal");
}
/* Mapping */
+NODE_DEFINE(MappingNode)
+{
+ NodeType* type = NodeType::add("mapping", create, NodeType::SHADER);
+
+ TEXTURE_MAPPING_DEFINE(MappingNode);
+
+ SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_POINT(vector, "Vector");
+
+ return type;
+}
+
MappingNode::MappingNode()
-: ShaderNode("mapping")
+: ShaderNode(node_type)
{
- add_input("Vector", SHADER_SOCKET_POINT);
- add_output("Vector", SHADER_SOCKET_POINT);
}
void MappingNode::compile(SVMCompiler& compiler)
@@ -1536,146 +1561,170 @@ void MappingNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mapping");
}
+/* RGBToBW */
+
+NODE_DEFINE(RGBToBWNode)
+{
+ 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");
+
+ return type;
+}
+
+RGBToBWNode::RGBToBWNode()
+: ShaderNode(node_type)
+{
+}
+
+void RGBToBWNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(linear_rgb_to_gray(color));
+ }
+}
+
+void RGBToBWNode::compile(SVMCompiler& compiler)
+{
+ compiler.add_node(NODE_CONVERT,
+ NODE_CONVERT_CF,
+ compiler.stack_assign(inputs[0]),
+ compiler.stack_assign(outputs[0]));
+}
+
+void RGBToBWNode::compile(OSLCompiler& compiler)
+{
+ compiler.add(this, "node_rgb_to_bw");
+}
+
/* Convert */
-ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool autoconvert)
-: ShaderNode("convert")
+const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
+bool ConvertNode::initialized = ConvertNode::register_types();
+
+Node* ConvertNode::create(const NodeType *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;
+}
+
+ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
+: ShaderNode(node_types[from_][to_])
{
from = from_;
to = to_;
- if(autoconvert) {
- if(from == to)
- special_type = SHADER_SPECIAL_TYPE_PROXY;
- else
- special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
- }
-
- if(from == SHADER_SOCKET_FLOAT)
- add_input("Val", SHADER_SOCKET_FLOAT);
- else if(from == SHADER_SOCKET_INT)
- add_input("ValInt", SHADER_SOCKET_INT);
- else if(from == SHADER_SOCKET_COLOR)
- add_input("Color", SHADER_SOCKET_COLOR);
- else if(from == SHADER_SOCKET_VECTOR)
- add_input("Vector", SHADER_SOCKET_VECTOR);
- else if(from == SHADER_SOCKET_POINT)
- add_input("Point", SHADER_SOCKET_POINT);
- else if(from == SHADER_SOCKET_NORMAL)
- add_input("Normal", SHADER_SOCKET_NORMAL);
- else if(from == SHADER_SOCKET_STRING)
- add_input("String", SHADER_SOCKET_STRING);
- else if(from == SHADER_SOCKET_CLOSURE)
- add_input("Closure", SHADER_SOCKET_CLOSURE);
- else
- assert(0);
-
- if(to == SHADER_SOCKET_FLOAT)
- add_output("Val", SHADER_SOCKET_FLOAT);
- else if(to == SHADER_SOCKET_INT)
- add_output("ValInt", SHADER_SOCKET_INT);
- else if(to == SHADER_SOCKET_COLOR)
- add_output("Color", SHADER_SOCKET_COLOR);
- else if(to == SHADER_SOCKET_VECTOR)
- add_output("Vector", SHADER_SOCKET_VECTOR);
- else if(to == SHADER_SOCKET_POINT)
- add_output("Point", SHADER_SOCKET_POINT);
- else if(to == SHADER_SOCKET_NORMAL)
- add_output("Normal", SHADER_SOCKET_NORMAL);
- else if(to == SHADER_SOCKET_STRING)
- add_output("String", SHADER_SOCKET_STRING);
- else if(to == SHADER_SOCKET_CLOSURE)
- add_output("Closure", SHADER_SOCKET_CLOSURE);
- else
- assert(0);
+ if(from == to)
+ special_type = SHADER_SPECIAL_TYPE_PROXY;
+ else if(autoconvert)
+ special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
}
-bool ConvertNode::constant_fold(ShaderGraph * /*graph*/,
- ShaderOutput * /*socket*/,
- float3 *optimized_value)
+void ConvertNode::constant_fold(const ConstantFolder& folder)
{
- ShaderInput *in = inputs[0];
- float3 value = in->value;
+ /* 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(in->link == NULL) {
- if(from == SHADER_SOCKET_FLOAT) {
- if(to == SHADER_SOCKET_INT)
- /* float to int */
- return false;
- else
- /* float to float3 */
- *optimized_value = make_float3(value.x, value.x, value.x);
- }
- else if(from == SHADER_SOCKET_INT) {
- if(to == SHADER_SOCKET_FLOAT)
- /* int to float */
- return false;
- else
- /* int to vector/point/normal */
- return false;
- }
- else if(to == SHADER_SOCKET_FLOAT) {
- if(from == SHADER_SOCKET_COLOR)
- /* color to float */
- optimized_value->x = linear_rgb_to_gray(value);
- else
- /* vector/point/normal to float */
- optimized_value->x = average(value);
- }
- else if(to == SHADER_SOCKET_INT) {
- if(from == SHADER_SOCKET_COLOR)
- /* color to int */
- return false;
- else
- /* vector/point/normal to int */
- return false;
+ 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 {
- *optimized_value = value;
+ else if(SocketType::is_float3(from)) {
+ if(to == SocketType::FLOAT) {
+ if(from == SocketType::COLOR) {
+ /* color to float */
+ folder.make_constant(linear_rgb_to_gray(value_color));
+ }
+ else {
+ /* vector/point/normal to float */
+ folder.make_constant(average(value_vector));
+ }
+ }
+ else if(SocketType::is_float3(to)) {
+ folder.make_constant(value_color);
+ }
}
-
- return true;
}
-
- return false;
}
void ConvertNode::compile(SVMCompiler& compiler)
{
- /* constant folding should eliminate proxy nodes */
- assert(from != to);
+ /* 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 == SHADER_SOCKET_FLOAT) {
- if(to == SHADER_SOCKET_INT)
+ 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 == SHADER_SOCKET_INT) {
- if(to == SHADER_SOCKET_FLOAT)
+ 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 == SHADER_SOCKET_FLOAT) {
- if(from == SHADER_SOCKET_COLOR)
+ 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 == SHADER_SOCKET_INT) {
- if(from == SHADER_SOCKET_COLOR)
+ 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
@@ -1691,27 +1740,27 @@ void ConvertNode::compile(SVMCompiler& compiler)
else {
/* set 0,0,0 value */
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
- compiler.add_node(NODE_VALUE_V, in->value);
+ compiler.add_node(NODE_VALUE_V, value_color);
}
}
}
void ConvertNode::compile(OSLCompiler& compiler)
{
- /* constant folding should eliminate proxy nodes */
- assert(from != to);
+ /* proxy nodes should have been removed at this point */
+ assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
- if(from == SHADER_SOCKET_FLOAT)
+ if(from == SocketType::FLOAT)
compiler.add(this, "node_convert_from_float");
- else if(from == SHADER_SOCKET_INT)
+ else if(from == SocketType::INT)
compiler.add(this, "node_convert_from_int");
- else if(from == SHADER_SOCKET_COLOR)
+ else if(from == SocketType::COLOR)
compiler.add(this, "node_convert_from_color");
- else if(from == SHADER_SOCKET_VECTOR)
+ else if(from == SocketType::VECTOR)
compiler.add(this, "node_convert_from_vector");
- else if(from == SHADER_SOCKET_POINT)
+ else if(from == SocketType::POINT)
compiler.add(this, "node_convert_from_point");
- else if(from == SHADER_SOCKET_NORMAL)
+ else if(from == SocketType::NORMAL)
compiler.add(this, "node_convert_from_normal");
else
assert(0);
@@ -1719,23 +1768,10 @@ void ConvertNode::compile(OSLCompiler& compiler)
/* BSDF Closure */
-BsdfNode::BsdfNode(bool scattering_)
-: ShaderNode("bsdf"), scattering(scattering_)
+BsdfNode::BsdfNode(const NodeType *node_type)
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
-
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-
- if(scattering) {
- closure = CLOSURE_BSSRDF_CUBIC_ID;
- add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
- }
- else {
- closure = CLOSURE_BSDF_DIFFUSE_ID;
- add_output("BSDF", SHADER_SOCKET_CLOSURE);
- }
}
void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4)
@@ -1747,9 +1783,9 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
- int normal_offset = compiler.stack_assign_if_linked(normal_in);
+ 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;
@@ -1759,8 +1795,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
(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)? param1->value.x: 0.0f),
- __float_as_int((param2)? param2->value.x: 0.0f));
+ __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);
}
@@ -1777,29 +1813,36 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/)
/* Anisotropic BSDF Closure */
-static ShaderEnum aniso_distribution_init()
+NODE_DEFINE(AnisotropicBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
- enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
+ 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);
- return enm;
-}
+ 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_FLOAT(roughness, "Roughness", 0.2f);
+ SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
+ SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
-ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init();
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
AnisotropicBsdfNode::AnisotropicBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
- distribution = ustring("GGX");
-
- add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
- add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f);
}
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -1816,45 +1859,54 @@ void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attrib
void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
- 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)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_anisotropic_bsdf");
}
/* Glossy BSDF Closure */
-static ShaderEnum glossy_distribution_init()
+NODE_DEFINE(GlossyBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
- enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
- enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+ 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);
- return enm;
-}
+ 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.2f);
-ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init();
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
GlossyBsdfNode::GlossyBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
- distribution = ustring("GGX");
- distribution_orig = ustring("");
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
+ distribution_orig = NBUILTIN_CLOSURES;
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1863,67 +1915,75 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness <= 1e-4f) {
+ distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool GlossyBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness <= 1e-4f;
}
void GlossyBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[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);
}
void GlossyBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_glossy_bsdf");
}
/* Glass BSDF Closure */
-static ShaderEnum glass_distribution_init()
+NODE_DEFINE(GlassBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
- enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+ 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);
- return enm;
-}
+ 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");
-ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init();
+ return type;
+}
GlassBsdfNode::GlassBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
- distribution = ustring("Sharp");
- distribution_orig = ustring("");
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+ distribution_orig = NBUILTIN_CLOSURES;
}
void GlassBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1932,67 +1992,75 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness <= 1e-4f) {
+ distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool GlassBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness <= 1e-4f;
}
void GlassBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[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"));
}
void GlassBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_glass_bsdf");
}
/* Refraction BSDF Closure */
-static ShaderEnum refraction_distribution_init()
+NODE_DEFINE(RefractionBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
- enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID);
- enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
- enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+ 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);
- return enm;
-}
+ 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);
-ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init();
+ SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
RefractionBsdfNode::RefractionBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_REFRACTION_ID;
- distribution = ustring("Sharp");
- distribution_orig = ustring("");
-
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+ distribution_orig = NBUILTIN_CLOSURES;
}
void RefractionBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -2001,26 +2069,26 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness <= 1e-4f) {
+ distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool RefractionBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness <= 1e-4f;
}
void RefractionBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_REFRACTION_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
@@ -2030,53 +2098,71 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler)
void RefractionBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter(this, "distribution");
compiler.add(this, "node_refraction_bsdf");
}
/* Toon BSDF Closure */
-static ShaderEnum toon_component_init()
+NODE_DEFINE(ToonBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
- enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
- enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
+ 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);
- return enm;
-}
+ 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");
-ShaderEnum ToonBsdfNode::component_enum = toon_component_init();
+ return type;
+}
ToonBsdfNode::ToonBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- component = ustring("Diffuse");
-
- add_input("Size", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
}
void ToonBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)component_enum[component];
+ closure = component;
BsdfNode::compile(compiler, input("Size"), input("Smooth"));
}
void ToonBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("component", component);
+ 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);
+
+ 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");
+
+ return type;
+}
+
VelvetBsdfNode::VelvetBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
-
- add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f);
}
void VelvetBsdfNode::compile(SVMCompiler& compiler)
@@ -2091,10 +2177,24 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler)
/* Diffuse BSDF Closure */
+NODE_DEFINE(DiffuseBsdfNode)
+{
+ 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_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
DiffuseBsdfNode::DiffuseBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_DIFFUSE_ID;
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
}
void DiffuseBsdfNode::compile(SVMCompiler& compiler)
@@ -2108,33 +2208,40 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler)
}
/* Disney BSDF Closure */
+NODE_DEFINE(DisneyBsdfNode)
+{
+ NodeType* type = NodeType::add("disney_bsdf", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(base_color, "BaseColor", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_COLOR(subsurface_color, "SubsurfaceColor", make_float3(0.8f, 0.8f, 0.8f));
+ SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
+ SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f);
+ SOCKET_IN_FLOAT(specular, "Specular", 0.0f);
+ SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+ SOCKET_IN_FLOAT(specularTint, "SpecularTint", 0.0f);
+ SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
+ SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
+ SOCKET_IN_FLOAT(sheenTint, "SheenTint", 0.0f);
+ SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f);
+ SOCKET_IN_FLOAT(clearcoatGloss, "ClearcoatGloss", 0.0f);
+ SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
+ SOCKET_IN_FLOAT(transparency, "Transparency", 0.0f);
+ SOCKET_IN_FLOAT(refractionRoughness, "RefractionRoughness", 0.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ SOCKET_IN_NORMAL(clearcoatNormal, "ClearcoatNormal", 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;
+}
+
DisneyBsdfNode::DisneyBsdfNode()
- : ShaderNode("bsdf")
+ : ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
closure = CLOSURE_BSDF_DISNEY_ID;
-
- add_input("BaseColor", SHADER_SOCKET_COLOR, make_float3(0.646f, 0.415f, 0.017f));
- add_input("SubsurfaceColor", SHADER_SOCKET_COLOR, make_float3(0.646f, 0.415f, 0.017f));
- add_input("Metallic", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Subsurface", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Specular", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("SpecularTint", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Anisotropic", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Sheen", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("SheenTint", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Clearcoat", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("ClearcoatGloss", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f);
- add_input("Transparency", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("RefractionRoughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("ClearcoatNormal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-
- add_output("BSDF", SHADER_SOCKET_CLOSURE);
}
void DisneyBsdfNode::compile(SVMCompiler& compiler, ShaderInput *metallic, ShaderInput *subsurface,
@@ -2176,8 +2283,8 @@ void DisneyBsdfNode::compile(SVMCompiler& compiler, ShaderInput *metallic, Shade
compiler.stack_assign(metallic),
compiler.stack_assign(subsurface),
compiler.closure_mix_weight_offset()),
- __float_as_int(metallic->value.x),
- __float_as_int(subsurface->value.x));
+ __float_as_int((metallic) ? get_float(metallic->socket_type) : 0.0f),
+ __float_as_int((subsurface) ? get_float(subsurface->socket_type) : 0.0f));
compiler.add_node(normal_offset, tangent_offset,
compiler.encode_uchar4(specular_offset, roughness_offset, specularTint_offset, anisotropic_offset),
@@ -2186,13 +2293,17 @@ void DisneyBsdfNode::compile(SVMCompiler& compiler, ShaderInput *metallic, Shade
compiler.add_node(compiler.encode_uchar4(ior_offset, transparency_offset, refr_roughness_offset, SVM_STACK_INVALID),
SVM_STACK_INVALID, SVM_STACK_INVALID, 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(base_color_in->value.x), __float_as_int(base_color_in->value.y), __float_as_int(base_color_in->value.z));
+ __float_as_int(bc_default.x), __float_as_int(bc_default.y), __float_as_int(bc_default.z));
compiler.add_node(clearcoat_normal_offset, SVM_STACK_INVALID, 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(subsurface_color_in->value.x), __float_as_int(subsurface_color_in->value.y), __float_as_int(subsurface_color_in->value.z));
+ __float_as_int(ss_default.x), __float_as_int(ss_default.y), __float_as_int(ss_default.z));
}
void DisneyBsdfNode::compile(SVMCompiler& compiler)
@@ -2216,7 +2327,21 @@ bool DisneyBsdfNode::has_bssrdf_bump()
/* Translucent BSDF Closure */
+NODE_DEFINE(TranslucentBsdfNode)
+{
+ 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_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
TranslucentBsdfNode::TranslucentBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_TRANSLUCENT_ID;
}
@@ -2233,9 +2358,21 @@ void TranslucentBsdfNode::compile(OSLCompiler& compiler)
/* Transparent BSDF Closure */
+NODE_DEFINE(TransparentBsdfNode)
+{
+ 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_OUT_CLOSURE(BSDF, "BSDF");
+
+ return type;
+}
+
TransparentBsdfNode::TransparentBsdfNode()
+: BsdfNode(node_type)
{
- name = "transparent";
closure = CLOSURE_BSDF_TRANSPARENT_ID;
}
@@ -2251,39 +2388,45 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler)
/* Subsurface Scattering Closure */
-static ShaderEnum subsurface_falloff_init()
+NODE_DEFINE(SubsurfaceScatteringNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
- enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID);
- enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
- enm.insert("Burley", CLOSURE_BSSRDF_BURLEY_ID);
+ 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);
- return enm;
-}
+ 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);
+ 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");
-ShaderEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init();
+ return type;
+}
SubsurfaceScatteringNode::SubsurfaceScatteringNode()
-: BsdfNode(true)
+: BsdfNode(node_type)
{
- name = "subsurface_scattering";
- closure = CLOSURE_BSSRDF_CUBIC_ID;
-
- add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f);
- add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f));
- add_input("Sharpness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Texture Blur", SHADER_SOCKET_FLOAT, 1.0f);
+ closure = falloff;
}
void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
{
+ closure = falloff;
BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
}
void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("Falloff", falloff_enum[closure]);
+ closure = falloff;
+ compiler.parameter(this, "falloff");
compiler.add(this, "node_subsurface_scattering");
}
@@ -2296,14 +2439,22 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
/* Emissive Closure */
-EmissionNode::EmissionNode()
-: ShaderNode("emission")
+NODE_DEFINE(EmissionNode)
{
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ NodeType* type = NodeType::add("emission", create, NodeType::SHADER);
- add_output("Emission", SHADER_SOCKET_CLOSURE);
+ 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");
+
+ return type;
+}
+
+EmissionNode::EmissionNode()
+: ShaderNode(node_type)
+{
}
void EmissionNode::compile(SVMCompiler& compiler)
@@ -2314,10 +2465,10 @@ void EmissionNode::compile(SVMCompiler& compiler)
if(color_in->link || strength_in->link) {
compiler.add_node(NODE_EMISSION_WEIGHT,
compiler.stack_assign(color_in),
- compiler.stack_assign(strength_in));
+ compiler.stack_assign(strength_in));
}
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
}
@@ -2327,25 +2478,35 @@ void EmissionNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_emission");
}
-bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+void EmissionNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength_in->value.x == 0.0f));
+ if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength == 0.0f)) {
+ folder.discard();
+ }
}
/* Background Closure */
-BackgroundNode::BackgroundNode()
-: ShaderNode("background")
+NODE_DEFINE(BackgroundNode)
{
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ 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_OUT_CLOSURE(background, "Background");
+
+ return type;
+}
- add_output("Background", SHADER_SOCKET_CLOSURE);
+BackgroundNode::BackgroundNode()
+: ShaderNode(node_type)
+{
}
void BackgroundNode::compile(SVMCompiler& compiler)
@@ -2359,7 +2520,7 @@ void BackgroundNode::compile(SVMCompiler& compiler)
compiler.stack_assign(strength_in));
}
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength);
compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
}
@@ -2369,24 +2530,34 @@ void BackgroundNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_background");
}
-bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+void BackgroundNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength_in->value.x == 0.0f));
+ if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength == 0.0f)) {
+ folder.discard();
+ }
}
/* Holdout Closure */
-HoldoutNode::HoldoutNode()
-: ShaderNode("holdout")
+NODE_DEFINE(HoldoutNode)
{
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
- add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ 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);
- add_output("Holdout", SHADER_SOCKET_CLOSURE);
+ SOCKET_OUT_CLOSURE(holdout, "Holdout");
+
+ return type;
+}
+
+HoldoutNode::HoldoutNode()
+: ShaderNode(node_type)
+{
}
void HoldoutNode::compile(SVMCompiler& compiler)
@@ -2404,14 +2575,22 @@ void HoldoutNode::compile(OSLCompiler& compiler)
/* Ambient Occlusion */
-AmbientOcclusionNode::AmbientOcclusionNode()
-: ShaderNode("ambient_occlusion")
+NODE_DEFINE(AmbientOcclusionNode)
{
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
- add_output("AO", SHADER_SOCKET_CLOSURE);
+ SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_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(AO, "AO");
+
+ return type;
+}
+
+AmbientOcclusionNode::AmbientOcclusionNode()
+: ShaderNode(node_type)
+{
}
void AmbientOcclusionNode::compile(SVMCompiler& compiler)
@@ -2421,7 +2600,7 @@ void AmbientOcclusionNode::compile(SVMCompiler& compiler)
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset());
}
@@ -2433,16 +2612,10 @@ void AmbientOcclusionNode::compile(OSLCompiler& compiler)
/* Volume Closure */
-VolumeNode::VolumeNode()
-: ShaderNode("volume")
+VolumeNode::VolumeNode(const NodeType *node_type)
+: ShaderNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Density", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-
- add_output("Volume", SHADER_SOCKET_CLOSURE);
}
void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
@@ -2452,15 +2625,15 @@ void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ 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)? param1->value.x: 0.0f),
- __float_as_int((param2)? param2->value.x: 0.0f));
+ __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)
@@ -2475,7 +2648,21 @@ void VolumeNode::compile(OSLCompiler& /*compiler*/)
/* Absorption Volume Closure */
+NODE_DEFINE(AbsorptionVolumeNode)
+{
+ 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_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
AbsorptionVolumeNode::AbsorptionVolumeNode()
+: VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_ABSORPTION_ID;
}
@@ -2492,11 +2679,24 @@ void AbsorptionVolumeNode::compile(OSLCompiler& compiler)
/* Scatter Volume Closure */
+NODE_DEFINE(ScatterVolumeNode)
+{
+ 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_OUT_CLOSURE(volume, "Volume");
+
+ return type;
+}
+
ScatterVolumeNode::ScatterVolumeNode()
+: VolumeNode(node_type)
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-
- add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f);
}
void ScatterVolumeNode::compile(SVMCompiler& compiler)
@@ -2511,59 +2711,71 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler)
/* Hair BSDF Closure */
-static ShaderEnum hair_component_init()
+NODE_DEFINE(HairBsdfNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
- enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
- enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+ 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);
- return enm;
-}
+ 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");
-ShaderEnum HairBsdfNode::component_enum = hair_component_init();
+ return type;
+}
HairBsdfNode::HairBsdfNode()
+: BsdfNode(node_type)
{
closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
- component = ustring("Reflection");
-
- add_input("Offset", SHADER_SOCKET_FLOAT);
- add_input("RoughnessU", SHADER_SOCKET_FLOAT);
- add_input("RoughnessV", SHADER_SOCKET_FLOAT);
- add_input("Tangent", SHADER_SOCKET_VECTOR);
}
void HairBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)component_enum[component];
+ closure = component;
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
}
void HairBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("component", component);
-
+ compiler.parameter(this, "component");
compiler.add(this, "node_hair_bsdf");
}
/* Geometry */
+NODE_DEFINE(GeometryNode)
+{
+ 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_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;
+}
+
GeometryNode::GeometryNode()
-: ShaderNode("geometry")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
-
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Position", SHADER_SOCKET_POINT);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("Tangent", SHADER_SOCKET_NORMAL);
- add_output("True Normal", SHADER_SOCKET_NORMAL);
- add_output("Incoming", SHADER_SOCKET_VECTOR);
- add_output("Parametric", SHADER_SOCKET_POINT);
- add_output("Backfacing", SHADER_SOCKET_FLOAT);
- add_output("Pointiness", SHADER_SOCKET_FLOAT);
}
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2658,21 +2870,30 @@ void GeometryNode::compile(OSLCompiler& compiler)
/* TextureCoordinate */
-TextureCoordinateNode::TextureCoordinateNode()
-: ShaderNode("texture_coordinate")
+NODE_DEFINE(TextureCoordinateNode)
{
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Generated", SHADER_SOCKET_POINT);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("UV", SHADER_SOCKET_POINT);
- add_output("Object", SHADER_SOCKET_POINT);
- add_output("Camera", SHADER_SOCKET_POINT);
- add_output("Window", SHADER_SOCKET_POINT);
- add_output("Reflection", SHADER_SOCKET_NORMAL);
+ 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_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
- from_dupli = false;
- use_transform = false;
- ob_tfm = transform_identity();
+ 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;
+}
+
+TextureCoordinateNode::TextureCoordinateNode()
+: ShaderNode(node_type)
+{
}
void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2796,22 +3017,32 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
compiler.parameter("is_background", true);
if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.parameter("is_volume", true);
- compiler.parameter("use_transform", use_transform);
+ compiler.parameter(this, "use_transform");
Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
compiler.parameter("object_itfm", ob_itfm);
- compiler.parameter("from_dupli", from_dupli);
+ compiler.parameter(this, "from_dupli");
compiler.add(this, "node_texture_coordinate");
}
-UVMapNode::UVMapNode()
-: ShaderNode("uvmap")
+/* UV Map */
+
+NODE_DEFINE(UVMapNode)
{
- attribute = "";
- from_dupli = false;
+ NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER);
+
+ SOCKET_IN_STRING(attribute, "attribute", ustring(""));
+ SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
+
+ SOCKET_OUT_POINT(UV, "UV");
- add_output("UV", SHADER_SOCKET_POINT);
+ return type;
+}
+
+UVMapNode::UVMapNode()
+: ShaderNode(node_type)
+{
}
void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2870,28 +3101,36 @@ void UVMapNode::compile(OSLCompiler& compiler)
else
compiler.parameter("bump_offset", "center");
- compiler.parameter("from_dupli", from_dupli);
- compiler.parameter("name", attribute.c_str());
+ 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);
+
+ 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(transparent_depth, "Transparent Depth");
+ SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
+
+ return type;
+}
+
LightPathNode::LightPathNode()
-: ShaderNode("light_path")
-{
- add_output("Is Camera Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Singular Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT);
- add_output("Ray Length", SHADER_SOCKET_FLOAT);
- add_output("Ray Depth", SHADER_SOCKET_FLOAT);
- add_output("Transparent Depth", SHADER_SOCKET_FLOAT);
- add_output("Transmission Depth", SHADER_SOCKET_FLOAT);
+: ShaderNode(node_type)
+{
}
void LightPathNode::compile(SVMCompiler& compiler)
@@ -2967,14 +3206,23 @@ void LightPathNode::compile(OSLCompiler& compiler)
/* Light Falloff */
+NODE_DEFINE(LightFalloffNode)
+{
+ NodeType* type = NodeType::add("light_fallof", create, NodeType::SHADER);
+
+ 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");
+
+ return type;
+}
+
LightFalloffNode::LightFalloffNode()
-: ShaderNode("light_fallof")
+: ShaderNode(node_type)
{
- add_input("Strength", SHADER_SOCKET_FLOAT, 100.0f);
- add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
- add_output("Quadratic", SHADER_SOCKET_FLOAT);
- add_output("Linear", SHADER_SOCKET_FLOAT);
- add_output("Constant", SHADER_SOCKET_FLOAT);
}
void LightFalloffNode::compile(SVMCompiler& compiler)
@@ -3017,13 +3265,21 @@ void LightFalloffNode::compile(OSLCompiler& compiler)
/* Object Info */
+NODE_DEFINE(ObjectInfoNode)
+{
+ 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");
+
+ return type;
+}
+
ObjectInfoNode::ObjectInfoNode()
-: ShaderNode("object_info")
+: ShaderNode(node_type)
{
- add_output("Location", SHADER_SOCKET_VECTOR);
- add_output("Object Index", SHADER_SOCKET_FLOAT);
- add_output("Material Index", SHADER_SOCKET_FLOAT);
- add_output("Random", SHADER_SOCKET_FLOAT);
}
void ObjectInfoNode::compile(SVMCompiler& compiler)
@@ -3056,19 +3312,27 @@ void ObjectInfoNode::compile(OSLCompiler& compiler)
/* Particle Info */
-ParticleInfoNode::ParticleInfoNode()
-: ShaderNode("particle_info")
+NODE_DEFINE(ParticleInfoNode)
{
- add_output("Index", SHADER_SOCKET_FLOAT);
- add_output("Age", SHADER_SOCKET_FLOAT);
- add_output("Lifetime", SHADER_SOCKET_FLOAT);
- add_output("Location", SHADER_SOCKET_POINT);
+ NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_FLOAT(index, "Index");
+ SOCKET_OUT_FLOAT(age, "Age");
+ SOCKET_OUT_FLOAT(lifetime, "Lifetime");
+ SOCKET_OUT_POINT(location, "Location");
#if 0 /* not yet supported */
- add_output("Rotation", SHADER_SOCKET_QUATERNION);
+ SOCKET_OUT_QUATERNION(rotation, "Rotation");
#endif
- add_output("Size", SHADER_SOCKET_FLOAT);
- add_output("Velocity", SHADER_SOCKET_VECTOR);
- add_output("Angular Velocity", SHADER_SOCKET_VECTOR);
+ SOCKET_OUT_FLOAT(size, "Size");
+ SOCKET_OUT_VECTOR(velocity, "Velocity");
+ SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
+
+ return type;
+}
+
+ParticleInfoNode::ParticleInfoNode()
+: ShaderNode(node_type)
+{
}
void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3150,15 +3414,24 @@ void ParticleInfoNode::compile(OSLCompiler& compiler)
/* Hair Info */
+NODE_DEFINE(HairInfoNode)
+{
+ 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");
+#if 0 /*output for minimum hair width transparency - deactivated */
+ SOCKET_OUT_FLOAT(fade, "Fade");
+#endif
+
+ return type;
+}
+
HairInfoNode::HairInfoNode()
-: ShaderNode("hair_info")
+: ShaderNode(node_type)
{
- add_output("Is Strand", SHADER_SOCKET_FLOAT);
- add_output("Intercept", SHADER_SOCKET_FLOAT);
- add_output("Thickness", SHADER_SOCKET_FLOAT);
- add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
- /*output for minimum hair width transparency - deactivated*/
- /*add_output("Fade", SHADER_SOCKET_FLOAT);*/
}
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3212,19 +3485,24 @@ void HairInfoNode::compile(OSLCompiler& compiler)
/* Value */
-ValueNode::ValueNode()
-: ShaderNode("value")
+NODE_DEFINE(ValueNode)
{
- value = 0.0f;
+ NodeType* type = NodeType::add("value", create, NodeType::SHADER);
+
+ SOCKET_FLOAT(value, "Value", 0.0f);
+ SOCKET_OUT_FLOAT(value, "Value");
- add_output("Value", SHADER_SOCKET_FLOAT);
+ return type;
}
-bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
- float3 *optimized_value)
+ValueNode::ValueNode()
+: ShaderNode(node_type)
{
- *optimized_value = make_float3(value, value, value);
- return true;
+}
+
+void ValueNode::constant_fold(const ConstantFolder& folder)
+{
+ folder.make_constant(value);
}
void ValueNode::compile(SVMCompiler& compiler)
@@ -3242,19 +3520,24 @@ void ValueNode::compile(OSLCompiler& compiler)
/* Color */
-ColorNode::ColorNode()
-: ShaderNode("color")
+NODE_DEFINE(ColorNode)
{
- value = make_float3(0.0f, 0.0f, 0.0f);
+ NodeType* type = NodeType::add("color", create, NodeType::SHADER);
- add_output("Color", SHADER_SOCKET_COLOR);
+ SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
}
-bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
- float3 *optimized_value)
+ColorNode::ColorNode()
+: ShaderNode(node_type)
{
- *optimized_value = value;
- return true;
+}
+
+void ColorNode::constant_fold(const ConstantFolder& folder)
+{
+ folder.make_constant(value);
}
void ColorNode::compile(SVMCompiler& compiler)
@@ -3276,14 +3559,21 @@ void ColorNode::compile(OSLCompiler& compiler)
/* Add Closure */
+NODE_DEFINE(AddClosureNode)
+{
+ NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER);
+
+ SOCKET_IN_CLOSURE(closure1, "Closure1");
+ SOCKET_IN_CLOSURE(closure2, "Closure2");
+ SOCKET_OUT_CLOSURE(closure, "Closure");
+
+ return type;
+}
+
AddClosureNode::AddClosureNode()
-: ShaderNode("add_closure")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
-
- add_input("Closure1", SHADER_SOCKET_CLOSURE);
- add_input("Closure2", SHADER_SOCKET_CLOSURE);
- add_output("Closure", SHADER_SOCKET_CLOSURE);
}
void AddClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3296,17 +3586,39 @@ void AddClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_add_closure");
}
+void AddClosureNode::constant_fold(const ConstantFolder& folder)
+{
+ 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);
+ }
+}
+
/* Mix Closure */
+NODE_DEFINE(MixClosureNode)
+{
+ 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_OUT_CLOSURE(closure, "Closure");
+
+ return type;
+}
+
MixClosureNode::MixClosureNode()
-: ShaderNode("mix_closure")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
-
- add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Closure1", SHADER_SOCKET_CLOSURE);
- add_input("Closure2", SHADER_SOCKET_CLOSURE);
- add_output("Closure", SHADER_SOCKET_CLOSURE);
}
void MixClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3319,46 +3631,48 @@ void MixClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mix_closure");
}
-bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+void MixClosureNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *closure1_in = input("Closure1");
ShaderInput *closure2_in = input("Closure2");
- ShaderOutput *closure_out = output("Closure");
/* remove useless mix closures nodes */
if(closure1_in->link == closure2_in->link) {
- graph->relink(this, closure_out, closure1_in->link);
- return true;
+ 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 */
- if(closure1_in->link && closure2_in->link && !fac_in->link) {
+ /* 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_in->value.x == 0.0f) {
- graph->relink(this, closure_out, closure1_in->link);
- return true;
+ if(fac <= 0.0f) {
+ folder.bypass_or_discard(closure1_in);
}
/* factor 1.0 */
- else if(fac_in->value.x == 1.0f) {
- graph->relink(this, closure_out, closure2_in->link);
- return true;
+ else if(fac >= 1.0f) {
+ folder.bypass_or_discard(closure2_in);
}
}
-
- return false;
}
/* Mix Closure */
+NODE_DEFINE(MixClosureWeightNode)
+{
+ 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_OUT_FLOAT(weight1, "Weight1");
+ SOCKET_OUT_FLOAT(weight2, "Weight2");
+
+ return type;
+}
+
MixClosureWeightNode::MixClosureWeightNode()
-: ShaderNode("mix_closure_weight")
+: ShaderNode(node_type)
{
- add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
- add_output("Weight1", SHADER_SOCKET_FLOAT);
- add_output("Weight2", SHADER_SOCKET_FLOAT);
}
void MixClosureWeightNode::compile(SVMCompiler& compiler)
@@ -3383,12 +3697,38 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
/* Invert */
+NODE_DEFINE(InvertNode)
+{
+ 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_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
InvertNode::InvertNode()
-: ShaderNode("invert")
+: ShaderNode(node_type)
+{
+}
+
+void InvertNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_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);
+ }
+ }
}
void InvertNode::compile(SVMCompiler& compiler)
@@ -3410,46 +3750,46 @@ void InvertNode::compile(OSLCompiler& compiler)
/* Mix */
-MixNode::MixNode()
-: ShaderNode("mix")
+NODE_DEFINE(MixNode)
{
- type = ustring("Mix");
+ NodeType* type = NodeType::add("mix", create, NodeType::SHADER);
- use_clamp = false;
+ 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);
- add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
-}
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
-static ShaderEnum mix_type_init()
-{
- ShaderEnum enm;
+ 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));
- enm.insert("Mix", NODE_MIX_BLEND);
- enm.insert("Add", NODE_MIX_ADD);
- enm.insert("Multiply", NODE_MIX_MUL);
- enm.insert("Screen", NODE_MIX_SCREEN);
- enm.insert("Overlay", NODE_MIX_OVERLAY);
- enm.insert("Subtract", NODE_MIX_SUB);
- enm.insert("Divide", NODE_MIX_DIV);
- enm.insert("Difference", NODE_MIX_DIFF);
- enm.insert("Darken", NODE_MIX_DARK);
- enm.insert("Lighten", NODE_MIX_LIGHT);
- enm.insert("Dodge", NODE_MIX_DODGE);
- enm.insert("Burn", NODE_MIX_BURN);
- enm.insert("Hue", NODE_MIX_HUE);
- enm.insert("Saturation", NODE_MIX_SAT);
- enm.insert("Value", NODE_MIX_VAL);
- enm.insert("Color", NODE_MIX_COLOR);
- enm.insert("Soft Light", NODE_MIX_SOFT);
- enm.insert("Linear Light", NODE_MIX_LINEAR);
+ SOCKET_OUT_COLOR(color, "Color");
- return enm;
+ return type;
}
-ShaderEnum MixNode::type_enum = mix_type_init();
+MixNode::MixNode()
+: ShaderNode(node_type)
+{
+}
void MixNode::compile(SVMCompiler& compiler)
{
@@ -3462,7 +3802,7 @@ void MixNode::compile(SVMCompiler& compiler)
compiler.stack_assign(fac_in),
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in));
- compiler.add_node(NODE_MIX, type_enum[type], compiler.stack_assign(color_out));
+ 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));
@@ -3472,59 +3812,46 @@ void MixNode::compile(SVMCompiler& compiler)
void MixNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("Clamp", use_clamp);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "use_clamp");
compiler.add(this, "node_mix");
}
-bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * optimized_value)
+void MixNode::constant_fold(const ConstantFolder& folder)
{
- if(type != ustring("Mix")) {
- return false;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp);
}
+ else {
+ folder.fold_mix(type, use_clamp);
+ }
+}
- ShaderInput *fac_in = input("Fac");
- ShaderInput *color1_in = input("Color1");
- ShaderInput *color2_in = input("Color2");
- ShaderOutput *color_out = output("Color");
+/* Combine RGB */
- /* remove useless mix colors nodes */
- if(color1_in->link && color1_in->link == color2_in->link) {
- graph->relink(this, color_out, color1_in->link);
- return true;
- }
+NODE_DEFINE(CombineRGBNode)
+{
+ NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER);
- /* remove unused mix color input when factor is 0.0 or 1.0 */
- if(!fac_in->link) {
- /* factor 0.0 */
- if(fac_in->value.x == 0.0f) {
- if(color1_in->link)
- graph->relink(this, color_out, color1_in->link);
- else
- *optimized_value = color1_in->value;
- return true;
- }
- /* factor 1.0 */
- else if(fac_in->value.x == 1.0f) {
- if(color2_in->link)
- graph->relink(this, color_out, color2_in->link);
- else
- *optimized_value = color2_in->value;
- return true;
- }
- }
+ SOCKET_IN_FLOAT(r, "R", 0.0f);
+ SOCKET_IN_FLOAT(g, "G", 0.0f);
+ SOCKET_IN_FLOAT(b, "B", 0.0f);
- return false;
+ SOCKET_OUT_COLOR(image, "Image");
+
+ return type;
}
-/* Combine RGB */
CombineRGBNode::CombineRGBNode()
-: ShaderNode("combine_rgb")
+: ShaderNode(node_type)
+{
+}
+
+void CombineRGBNode::constant_fold(const ConstantFolder& folder)
{
- add_input("R", SHADER_SOCKET_FLOAT);
- add_input("G", SHADER_SOCKET_FLOAT);
- add_input("B", SHADER_SOCKET_FLOAT);
- add_output("Image", SHADER_SOCKET_COLOR);
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(r, g, b));
+ }
}
void CombineRGBNode::compile(SVMCompiler& compiler)
@@ -3553,13 +3880,30 @@ void CombineRGBNode::compile(OSLCompiler& compiler)
}
/* Combine XYZ */
+
+NODE_DEFINE(CombineXYZNode)
+{
+ 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_OUT_VECTOR(vector, "Vector");
+
+ return type;
+}
+
CombineXYZNode::CombineXYZNode()
-: ShaderNode("combine_xyz")
+: ShaderNode(node_type)
+{
+}
+
+void CombineXYZNode::constant_fold(const ConstantFolder& folder)
{
- add_input("X", SHADER_SOCKET_FLOAT);
- add_input("Y", SHADER_SOCKET_FLOAT);
- add_input("Z", SHADER_SOCKET_FLOAT);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(x, y, z));
+ }
}
void CombineXYZNode::compile(SVMCompiler& compiler)
@@ -3588,13 +3932,30 @@ void CombineXYZNode::compile(OSLCompiler& compiler)
}
/* Combine HSV */
+
+NODE_DEFINE(CombineHSVNode)
+{
+ 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_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
CombineHSVNode::CombineHSVNode()
-: ShaderNode("combine_hsv")
+: ShaderNode(node_type)
{
- add_input("H", SHADER_SOCKET_FLOAT);
- add_input("S", SHADER_SOCKET_FLOAT);
- add_input("V", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+void CombineHSVNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
+ }
}
void CombineHSVNode::compile(SVMCompiler& compiler)
@@ -3618,28 +3979,28 @@ void CombineHSVNode::compile(OSLCompiler& compiler)
}
/* Gamma */
-GammaNode::GammaNode()
-: ShaderNode("gamma")
+
+NODE_DEFINE(GammaNode)
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_input("Gamma", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ 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");
+
+ return type;
}
-bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+GammaNode::GammaNode()
+: ShaderNode(node_type)
{
- ShaderInput *color_in = input("Color");
- ShaderInput *gamma_in = input("Gamma");
+}
- if(socket == output("Color")) {
- if(color_in->link == NULL && gamma_in->link == NULL) {
- *optimized_value = svm_math_gamma_color(color_in->value,
- gamma_in->value.x);
- return true;
- }
+void GammaNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_gamma_color(color, gamma));
}
-
- return false;
}
void GammaNode::compile(SVMCompiler& compiler)
@@ -3660,13 +4021,30 @@ void GammaNode::compile(OSLCompiler& compiler)
}
/* Bright Contrast */
+
+NODE_DEFINE(BrightContrastNode)
+{
+ 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_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
BrightContrastNode::BrightContrastNode()
-: ShaderNode("brightness")
+: ShaderNode(node_type)
+{
+}
+
+void BrightContrastNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_input("Bright", SHADER_SOCKET_FLOAT);
- add_input("Contrast", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_brightness_contrast(color, bright, contrast));
+ }
}
void BrightContrastNode::compile(SVMCompiler& compiler)
@@ -3690,13 +4068,35 @@ void BrightContrastNode::compile(OSLCompiler& compiler)
}
/* Separate RGB */
+
+NODE_DEFINE(SeparateRGBNode)
+{
+ NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER);
+
+ SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f));
+
+ SOCKET_OUT_FLOAT(g, "R");
+ SOCKET_OUT_FLOAT(g, "G");
+ SOCKET_OUT_FLOAT(b, "B");
+
+ return type;
+}
+
SeparateRGBNode::SeparateRGBNode()
-: ShaderNode("separate_rgb")
+: ShaderNode(node_type)
+{
+}
+
+void SeparateRGBNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Image", SHADER_SOCKET_COLOR);
- add_output("R", SHADER_SOCKET_FLOAT);
- add_output("G", SHADER_SOCKET_FLOAT);
- add_output("B", SHADER_SOCKET_FLOAT);
+ 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)
@@ -3725,13 +4125,35 @@ void SeparateRGBNode::compile(OSLCompiler& compiler)
}
/* Separate XYZ */
+
+NODE_DEFINE(SeparateXYZNode)
+{
+ NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER);
+
+ 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");
+
+ return type;
+}
+
SeparateXYZNode::SeparateXYZNode()
-: ShaderNode("separate_xyz")
+: ShaderNode(node_type)
+{
+}
+
+void SeparateXYZNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("X", SHADER_SOCKET_FLOAT);
- add_output("Y", SHADER_SOCKET_FLOAT);
- add_output("Z", SHADER_SOCKET_FLOAT);
+ 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)
@@ -3760,13 +4182,37 @@ void SeparateXYZNode::compile(OSLCompiler& compiler)
}
/* Separate HSV */
+
+NODE_DEFINE(SeparateHSVNode)
+{
+ NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER);
+
+ 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");
+
+ return type;
+}
+
SeparateHSVNode::SeparateHSVNode()
-: ShaderNode("separate_hsv")
+: ShaderNode(node_type)
+{
+}
+
+void SeparateHSVNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("H", SHADER_SOCKET_FLOAT);
- add_output("S", SHADER_SOCKET_FLOAT);
- add_output("V", SHADER_SOCKET_FLOAT);
+ 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;
+ }
+ }
+ }
}
void SeparateHSVNode::compile(SVMCompiler& compiler)
@@ -3790,15 +4236,25 @@ void SeparateHSVNode::compile(OSLCompiler& compiler)
}
/* Hue Saturation Value */
+
+NODE_DEFINE(HSVNode)
+{
+ 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_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
HSVNode::HSVNode()
-: ShaderNode("hsv")
+: ShaderNode(node_type)
{
- add_input("Hue", SHADER_SOCKET_FLOAT);
- add_input("Saturation", SHADER_SOCKET_FLOAT);
- add_input("Value", SHADER_SOCKET_FLOAT);
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
}
void HSVNode::compile(SVMCompiler& compiler)
@@ -3828,14 +4284,22 @@ void HSVNode::compile(OSLCompiler& compiler)
/* Attribute */
-AttributeNode::AttributeNode()
-: ShaderNode("attribute")
+NODE_DEFINE(AttributeNode)
{
- attribute = "";
+ NodeType* type = NodeType::add("attribute", create, NodeType::SHADER);
+
+ SOCKET_STRING(attribute, "Attribute", ustring(""));
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_VECTOR(vector, "Vector");
+ SOCKET_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+AttributeNode::AttributeNode()
+: ShaderNode(node_type)
+{
}
void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3911,12 +4375,20 @@ void AttributeNode::compile(OSLCompiler& compiler)
/* Camera */
+NODE_DEFINE(CameraNode)
+{
+ 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");
+
+ return type;
+}
+
CameraNode::CameraNode()
-: ShaderNode("camera")
+: ShaderNode(node_type)
{
- add_output("View Vector", SHADER_SOCKET_VECTOR);
- add_output("View Z Depth", SHADER_SOCKET_FLOAT);
- add_output("View Distance", SHADER_SOCKET_FLOAT);
}
void CameraNode::compile(SVMCompiler& compiler)
@@ -3938,12 +4410,21 @@ void CameraNode::compile(OSLCompiler& compiler)
/* Fresnel */
+NODE_DEFINE(FresnelNode)
+{
+ 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_OUT_FLOAT(fac, "Fac");
+
+ return type;
+}
+
FresnelNode::FresnelNode()
-: ShaderNode("fresnel")
+: ShaderNode(node_type)
{
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
}
void FresnelNode::compile(SVMCompiler& compiler)
@@ -3954,7 +4435,7 @@ void FresnelNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_FRESNEL,
compiler.stack_assign(IOR_in),
- __float_as_int(IOR_in->value.x),
+ __float_as_int(IOR),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fac_out)));
@@ -3967,14 +4448,22 @@ void FresnelNode::compile(OSLCompiler& compiler)
/* Layer Weight */
-LayerWeightNode::LayerWeightNode()
-: ShaderNode("layer_weight")
+NODE_DEFINE(LayerWeightNode)
{
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f);
+ 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_OUT_FLOAT(fresnel, "Fresnel");
+ SOCKET_OUT_FLOAT(facing, "Facing");
+
+ return type;
+}
- add_output("Fresnel", SHADER_SOCKET_FLOAT);
- add_output("Facing", SHADER_SOCKET_FLOAT);
+LayerWeightNode::LayerWeightNode()
+: ShaderNode(node_type)
+{
}
void LayerWeightNode::compile(SVMCompiler& compiler)
@@ -3987,7 +4476,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler)
if(!fresnel_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend_in->value.x),
+ __float_as_int(blend),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fresnel_out)));
@@ -3996,7 +4485,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler)
if(!facing_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend_in->value.x),
+ __float_as_int(blend),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(facing_out)));
@@ -4010,13 +4499,20 @@ void LayerWeightNode::compile(OSLCompiler& compiler)
/* Wireframe */
+NODE_DEFINE(WireframeNode)
+{
+ 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");
+
+ return type;
+}
+
WireframeNode::WireframeNode()
-: ShaderNode("wireframe")
+: ShaderNode(node_type)
{
- add_input("Size", SHADER_SOCKET_FLOAT, 0.01f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
-
- use_pixel_size = false;
}
void WireframeNode::compile(SVMCompiler& compiler)
@@ -4049,17 +4545,25 @@ void WireframeNode::compile(OSLCompiler& compiler)
else {
compiler.parameter("bump_offset", "center");
}
- compiler.parameter("use_pixel_size", use_pixel_size);
+ compiler.parameter(this, "use_pixel_size");
compiler.add(this, "node_wireframe");
}
/* Wavelength */
+NODE_DEFINE(WavelengthNode)
+{
+ NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
WavelengthNode::WavelengthNode()
-: ShaderNode("wavelength")
+: ShaderNode(node_type)
{
- add_input("Wavelength", SHADER_SOCKET_FLOAT, 500.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
}
void WavelengthNode::compile(SVMCompiler& compiler)
@@ -4079,25 +4583,26 @@ void WavelengthNode::compile(OSLCompiler& compiler)
/* Blackbody */
-BlackbodyNode::BlackbodyNode()
-: ShaderNode("blackbody")
+NODE_DEFINE(BlackbodyNode)
{
- add_input("Temperature", SHADER_SOCKET_FLOAT, 1200.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
+ NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
}
-bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+BlackbodyNode::BlackbodyNode()
+: ShaderNode(node_type)
{
- ShaderInput *temperature_in = input("Temperature");
+}
- if(socket == output("Color")) {
- if(temperature_in->link == NULL) {
- *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
- return true;
- }
+void BlackbodyNode::constant_fold(const ConstantFolder& folder)
+{
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_blackbody_color(temperature));
}
-
- return false;
}
void BlackbodyNode::compile(SVMCompiler& compiler)
@@ -4117,15 +4622,22 @@ void BlackbodyNode::compile(OSLCompiler& compiler)
/* Output */
+NODE_DEFINE(OutputNode)
+{
+ NodeType* type = NodeType::add("output", create, NodeType::SHADER);
+
+ SOCKET_IN_CLOSURE(surface, "Surface");
+ SOCKET_IN_CLOSURE(volume, "Volume");
+ SOCKET_IN_FLOAT(displacement, "Displacement", 0.0f);
+ SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
+
+ return type;
+}
+
OutputNode::OutputNode()
-: ShaderNode("output")
+: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_OUTPUT;
-
- add_input("Surface", SHADER_SOCKET_CLOSURE);
- add_input("Volume", SHADER_SOCKET_CLOSURE);
- add_input("Displacement", SHADER_SOCKET_FLOAT);
- add_input("Normal", SHADER_SOCKET_NORMAL);
}
void OutputNode::compile(SVMCompiler& compiler)
@@ -4151,67 +4663,55 @@ void OutputNode::compile(OSLCompiler& compiler)
/* Math */
-MathNode::MathNode()
-: ShaderNode("math")
+NODE_DEFINE(MathNode)
{
- type = ustring("Add");
+ NodeType* type = NodeType::add("math", create, NodeType::SHADER);
- use_clamp = false;
+ 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);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
- add_input("Value1", SHADER_SOCKET_FLOAT);
- add_input("Value2", SHADER_SOCKET_FLOAT);
- add_output("Value", SHADER_SOCKET_FLOAT);
-}
+ SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
-static ShaderEnum math_type_init()
-{
- ShaderEnum enm;
+ SOCKET_IN_FLOAT(value1, "Value1", 0.0f);
+ SOCKET_IN_FLOAT(value2, "Value2", 0.0f);
- enm.insert("Add", NODE_MATH_ADD);
- enm.insert("Subtract", NODE_MATH_SUBTRACT);
- enm.insert("Multiply", NODE_MATH_MULTIPLY);
- enm.insert("Divide", NODE_MATH_DIVIDE);
- enm.insert("Sine", NODE_MATH_SINE);
- enm.insert("Cosine", NODE_MATH_COSINE);
- enm.insert("Tangent", NODE_MATH_TANGENT);
- enm.insert("Arcsine", NODE_MATH_ARCSINE);
- enm.insert("Arccosine", NODE_MATH_ARCCOSINE);
- enm.insert("Arctangent", NODE_MATH_ARCTANGENT);
- enm.insert("Power", NODE_MATH_POWER);
- enm.insert("Logarithm", NODE_MATH_LOGARITHM);
- enm.insert("Minimum", NODE_MATH_MINIMUM);
- enm.insert("Maximum", NODE_MATH_MAXIMUM);
- enm.insert("Round", NODE_MATH_ROUND);
- enm.insert("Less Than", NODE_MATH_LESS_THAN);
- enm.insert("Greater Than", NODE_MATH_GREATER_THAN);
- enm.insert("Modulo", NODE_MATH_MODULO);
- enm.insert("Absolute", NODE_MATH_ABSOLUTE);
+ SOCKET_OUT_FLOAT(value, "Value");
- return enm;
+ return type;
}
-ShaderEnum MathNode::type_enum = math_type_init();
-
-bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+MathNode::MathNode()
+: ShaderNode(node_type)
{
- ShaderInput *value1_in = input("Value1");
- ShaderInput *value2_in = input("Value2");
-
- if(socket == output("Value")) {
- if(value1_in->link == NULL && value2_in->link == NULL) {
- optimized_value->x = svm_math((NodeMath)type_enum[type],
- value1_in->value.x,
- value2_in->value.x);
-
- if(use_clamp) {
- optimized_value->x = saturate(optimized_value->x);
- }
+}
- return true;
- }
+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);
}
-
- return false;
}
void MathNode::compile(SVMCompiler& compiler)
@@ -4220,10 +4720,7 @@ void MathNode::compile(SVMCompiler& compiler)
ShaderInput *value2_in = input("Value2");
ShaderOutput *value_out = output("Value");
- compiler.add_node(NODE_MATH,
- type_enum[type],
- compiler.stack_assign(value1_in),
- compiler.stack_assign(value2_in));
+ 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) {
@@ -4234,66 +4731,62 @@ void MathNode::compile(SVMCompiler& compiler)
void MathNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("Clamp", use_clamp);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "use_clamp");
compiler.add(this, "node_math");
}
/* VectorMath */
-VectorMathNode::VectorMathNode()
-: ShaderNode("vector_math")
+NODE_DEFINE(VectorMathNode)
{
- type = ustring("Add");
+ NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER);
- add_input("Vector1", SHADER_SOCKET_VECTOR);
- add_input("Vector2", SHADER_SOCKET_VECTOR);
- add_output("Value", SHADER_SOCKET_FLOAT);
- add_output("Vector", SHADER_SOCKET_VECTOR);
-}
+ 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 ShaderEnum vector_math_type_init()
-{
- ShaderEnum enm;
+ 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));
- enm.insert("Add", NODE_VECTOR_MATH_ADD);
- enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT);
- enm.insert("Average", NODE_VECTOR_MATH_AVERAGE);
- enm.insert("Dot Product", NODE_VECTOR_MATH_DOT_PRODUCT);
- enm.insert("Cross Product", NODE_VECTOR_MATH_CROSS_PRODUCT);
- enm.insert("Normalize", NODE_VECTOR_MATH_NORMALIZE);
+ SOCKET_OUT_FLOAT(value, "Value");
+ SOCKET_OUT_VECTOR(vector, "Vector");
- return enm;
+ return type;
}
-ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
-
-bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+VectorMathNode::VectorMathNode()
+: ShaderNode(node_type)
{
- ShaderInput *vector1_in = input("Vector1");
- ShaderInput *vector2_in = input("Vector2");
+}
+void VectorMathNode::constant_fold(const ConstantFolder& folder)
+{
float value;
float3 vector;
- if(vector1_in->link == NULL && vector2_in->link == NULL) {
+ if(folder.all_inputs_constant()) {
svm_vector_math(&value,
&vector,
- (NodeVectorMath)type_enum[type],
- vector1_in->value,
- vector2_in->value);
+ type,
+ vector1,
+ vector2);
- if(socket == output("Value")) {
- optimized_value->x = value;
- return true;
+ if(folder.output == output("Value")) {
+ folder.make_constant(value);
}
- else if(socket == output("Vector")) {
- *optimized_value = vector;
- return true;
+ else if(folder.output == output("Vector")) {
+ folder.make_constant(vector);
}
}
-
- return false;
+ else {
+ folder.fold_vector_math(type);
+ }
}
void VectorMathNode::compile(SVMCompiler& compiler)
@@ -4304,7 +4797,7 @@ void VectorMathNode::compile(SVMCompiler& compiler)
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_MATH,
- type_enum[type],
+ type,
compiler.stack_assign(vector1_in),
compiler.stack_assign(vector2_in));
compiler.add_node(NODE_VECTOR_MATH,
@@ -4314,90 +4807,87 @@ void VectorMathNode::compile(SVMCompiler& compiler)
void VectorMathNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
+ compiler.parameter(this, "type");
compiler.add(this, "node_vector_math");
}
/* VectorTransform */
-VectorTransformNode::VectorTransformNode()
-: ShaderNode("vector_transform")
+NODE_DEFINE(VectorTransformNode)
{
- type = ustring("Vector");
- convert_from = ustring("world");
- convert_to = ustring("object");
+ NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER);
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("Vector", SHADER_SOCKET_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 ShaderEnum vector_transform_type_init()
-{
- ShaderEnum enm;
+ 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);
- enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
- enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
- enm.insert("Normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+ SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_OUT_VECTOR(vector, "Vector");
- return enm;
+ return type;
}
-static ShaderEnum vector_transform_convert_space_init()
+VectorTransformNode::VectorTransformNode()
+: ShaderNode(node_type)
{
- ShaderEnum enm;
-
- enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
- enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
- enm.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
-
- return enm;
}
-ShaderEnum VectorTransformNode::type_enum = vector_transform_type_init();
-ShaderEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init();
-
void VectorTransformNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector_in = input("Vector");
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_TRANSFORM,
- compiler.encode_uchar4(type_enum[type],
- convert_space_enum[convert_from],
- convert_space_enum[convert_to]),
+ 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)
{
- compiler.parameter("type", type);
- compiler.parameter("convert_from", convert_from);
- compiler.parameter("convert_to", convert_to);
+ compiler.parameter(this, "type");
+ compiler.parameter(this, "convert_from");
+ compiler.parameter(this, "convert_to");
compiler.add(this, "node_vector_transform");
}
/* BumpNode */
-BumpNode::BumpNode()
-: ShaderNode("bump")
+NODE_DEFINE(BumpNode)
{
- invert = false;
+ NodeType* type = NodeType::add("bump", create, NodeType::SHADER);
- special_type = SHADER_SPECIAL_TYPE_BUMP;
+ SOCKET_BOOLEAN(invert, "Invert", 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 */
- add_input("Height", SHADER_SOCKET_FLOAT);
+ 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_OUT_NORMAL(normal, "Normal");
- add_input("SampleCenter", SHADER_SOCKET_FLOAT);
- add_input("SampleX", SHADER_SOCKET_FLOAT);
- add_input("SampleY", SHADER_SOCKET_FLOAT);
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Distance", SHADER_SOCKET_FLOAT, 0.1f);
+ return type;
+}
- add_output("Normal", SHADER_SOCKET_NORMAL);
+BumpNode::BumpNode()
+: ShaderNode(node_type)
+{
+ special_type = SHADER_SPECIAL_TYPE_BUMP;
}
void BumpNode::compile(SVMCompiler& compiler)
@@ -4426,13 +4916,11 @@ void BumpNode::compile(SVMCompiler& compiler)
void BumpNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("invert", invert);
+ compiler.parameter(this, "invert");
compiler.add(this, "node_bump");
}
-bool BumpNode::constant_fold(ShaderGraph *graph,
- ShaderOutput * /*socket*/,
- float3 * /*optimized_value*/)
+void BumpNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *height_in = input("Height");
ShaderInput *normal_in = input("Normal");
@@ -4440,46 +4928,60 @@ bool BumpNode::constant_fold(ShaderGraph *graph,
if(height_in->link == NULL) {
if(normal_in->link == NULL) {
GeometryNode *geom = new GeometryNode();
- graph->add(geom);
- graph->relink(this, outputs[0], geom->output("Normal"));
+ folder.graph->add(geom);
+ folder.bypass(geom->output("Normal"));
}
else {
- graph->relink(this, outputs[0], normal_in->link);
+ folder.bypass(normal_in->link);
}
- return true;
}
/* TODO(sergey): Ignore bump with zero strength. */
-
- return false;
}
-/* RGBCurvesNode */
-RGBCurvesNode::RGBCurvesNode()
-: ShaderNode("rgb_curves")
+/* Curve node */
+
+CurvesNode::CurvesNode(const NodeType *node_type)
+: ShaderNode(node_type)
+{
+}
+
+void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in)
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+ ShaderInput *fac_in = input("Fac");
- min_x = 0.0f;
- max_x = 1.0f;
+ /* remove no-op node */
+ if(!fac_in->link && fac == 0.0f) {
+ folder.bypass(value_in->link);
+ }
+ /* evaluate fully constant node */
+ else 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;
+
+ 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));
+ }
}
-void RGBCurvesNode::compile(SVMCompiler& compiler)
+void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out)
{
if(curves.size() == 0)
return;
ShaderInput *fac_in = input("Fac");
- ShaderInput *color_in = input("Color");
- ShaderOutput *color_out = output("Color");
- compiler.add_node(NODE_RGB_CURVES,
+ compiler.add_node(type,
compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(color_in),
- compiler.stack_assign(color_out)),
+ compiler.stack_assign(value_in),
+ compiler.stack_assign(value_out)),
__float_as_int(min_x),
__float_as_int(max_x));
@@ -4488,72 +4990,149 @@ void RGBCurvesNode::compile(SVMCompiler& compiler)
compiler.add_node(float3_to_float4(curves[i]));
}
-void RGBCurvesNode::compile(OSLCompiler& compiler)
+void CurvesNode::compile(OSLCompiler& compiler, const char* name)
{
if(curves.size() == 0)
return;
compiler.parameter_color_array("ramp", curves);
- compiler.parameter("min_x", min_x);
- compiler.parameter("max_x", max_x);
- compiler.add(this, "node_rgb_curves");
+ compiler.parameter(this, "min_x");
+ compiler.parameter(this, "max_x");
+ compiler.add(this, name);
}
-/* VectorCurvesNode */
+void CurvesNode::compile(SVMCompiler& /*compiler*/)
+{
+ assert(0);
+}
-VectorCurvesNode::VectorCurvesNode()
-: ShaderNode("vector_curves")
+void CurvesNode::compile(OSLCompiler& /*compiler*/)
+{
+ assert(0);
+}
+
+/* RGBCurvesNode */
+
+NODE_DEFINE(RGBCurvesNode)
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ 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);
- min_x = 0.0f;
- 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_OUT_COLOR(value, "Color");
+
+ return type;
}
-void VectorCurvesNode::compile(SVMCompiler& compiler)
+RGBCurvesNode::RGBCurvesNode()
+: CurvesNode(node_type)
{
- if(curves.size() == 0)
- return;
+}
- ShaderInput *fac_in = input("Fac");
- ShaderInput *vector_in = input("Vector");
- ShaderOutput *vector_out = output("Vector");
+void RGBCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+ CurvesNode::constant_fold(folder, input("Color"));
+}
- compiler.add_node(NODE_VECTOR_CURVES,
- compiler.encode_uchar4(compiler.stack_assign(fac_in),
- compiler.stack_assign(vector_in),
- compiler.stack_assign(vector_out)),
- __float_as_int(min_x),
- __float_as_int(max_x));
+void RGBCurvesNode::compile(SVMCompiler& compiler)
+{
+ CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
+}
- compiler.add_node(curves.size());
- for(int i = 0; i < curves.size(); i++)
- compiler.add_node(float3_to_float4(curves[i]));
+void RGBCurvesNode::compile(OSLCompiler& compiler)
+{
+ CurvesNode::compile(compiler, "node_rgb_curves");
}
-void VectorCurvesNode::compile(OSLCompiler& compiler)
+/* VectorCurvesNode */
+
+NODE_DEFINE(VectorCurvesNode)
{
- if(curves.size() == 0)
- return;
+ NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER);
- compiler.parameter_color_array("ramp", curves);
- compiler.parameter("min_x", min_x);
- compiler.parameter("max_x", max_x);
- compiler.add(this, "node_vector_curves");
+ 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_OUT_VECTOR(value, "Vector");
+
+ return type;
+}
+
+VectorCurvesNode::VectorCurvesNode()
+: CurvesNode(node_type)
+{
+}
+
+void VectorCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+ CurvesNode::constant_fold(folder, input("Vector"));
+}
+
+void VectorCurvesNode::compile(SVMCompiler& compiler)
+{
+ CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
+}
+
+void VectorCurvesNode::compile(OSLCompiler& compiler)
+{
+ CurvesNode::compile(compiler, "node_vector_curves");
}
/* RGBRampNode */
+NODE_DEFINE(RGBRampNode)
+{
+ 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_IN_FLOAT(fac, "Fac", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
RGBRampNode::RGBRampNode()
-: ShaderNode("rgb_ramp")
+: ShaderNode(node_type)
+{
+}
+
+void RGBRampNode::constant_fold(const ConstantFolder& folder)
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
+ 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);
- interpolate = true;
+ /* 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;
+
+ 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)
@@ -4584,18 +5163,26 @@ void RGBRampNode::compile(OSLCompiler& compiler)
compiler.parameter_color_array("ramp_color", ramp);
compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
- compiler.parameter("ramp_interpolate", interpolate);
+ compiler.parameter(this, "interpolate");
compiler.add(this, "node_rgb_ramp");
}
/* Set Normal Node */
+NODE_DEFINE(SetNormalNode)
+{
+ 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");
+
+ return type;
+}
+
SetNormalNode::SetNormalNode()
-: ShaderNode("set_normal")
+: ShaderNode(node_type)
{
- add_input("Direction", SHADER_SOCKET_VECTOR);
- add_output("Normal", SHADER_SOCKET_NORMAL);
}
void SetNormalNode::compile(SVMCompiler& compiler)
@@ -4613,20 +5200,73 @@ void SetNormalNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_set_normal");
}
-/* OSLScriptNode */
+/* OSLNode */
-OSLScriptNode::OSLScriptNode()
-: ShaderNode("osl_script")
+OSLNode::OSLNode()
+: ShaderNode(new NodeType(NodeType::SHADER))
{
special_type = SHADER_SPECIAL_TYPE_SCRIPT;
}
-void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
+OSLNode::~OSLNode()
+{
+ delete type;
+}
+
+ShaderNode *OSLNode::clone() const
+{
+ return OSLNode::create(this->inputs.size(), this);
+}
+
+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;
+
+ 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);
+
+ OSLNode *node = new(node_memory) OSLNode(*from);
+ node->type = new NodeType(*(from->type));
+ return node;
+ }
+}
+
+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;
+}
+
+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);
+}
+
+void OSLNode::add_output(ustring name, SocketType::Type socket_type)
+{
+ const_cast<NodeType*>(type)->register_output(name, name, socket_type);
+}
+
+void OSLNode::compile(SVMCompiler&)
{
/* doesn't work for SVM, obviously ... */
}
-void OSLScriptNode::compile(OSLCompiler& compiler)
+void OSLNode::compile(OSLCompiler& compiler)
{
if(!filepath.empty())
compiler.add(this, filepath.c_str(), true);
@@ -4636,37 +5276,37 @@ void OSLScriptNode::compile(OSLCompiler& compiler)
/* Normal Map */
-static ShaderEnum normal_map_space_init()
+NODE_DEFINE(NormalMapNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER);
- enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT);
- enm.insert("Object", NODE_NORMAL_MAP_OBJECT);
- enm.insert("World", NODE_NORMAL_MAP_WORLD);
- enm.insert("Blender Object", NODE_NORMAL_MAP_BLENDER_OBJECT);
- enm.insert("Blender World", NODE_NORMAL_MAP_BLENDER_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);
+ 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_TANGENT_RADIAL);
- return enm;
-}
+ SOCKET_STRING(attribute, "Attribute", ustring(""));
-ShaderEnum NormalMapNode::space_enum = normal_map_space_init();
+ 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));
-NormalMapNode::NormalMapNode()
-: ShaderNode("normal_map")
-{
- space = ustring("Tangent");
- attribute = ustring("");
+ SOCKET_OUT_NORMAL(normal, "Normal");
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Color", SHADER_SOCKET_COLOR);
+ return type;
+}
- add_output("Normal", SHADER_SOCKET_NORMAL);
+NormalMapNode::NormalMapNode()
+: ShaderNode(node_type)
+{
}
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
- if(shader->has_surface && space == ustring("Tangent")) {
+ if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
@@ -4689,7 +5329,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
ShaderOutput *normal_out = output("Normal");
int attr = 0, attr_sign = 0;
- if(space == ustring("Tangent")) {
+ if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
@@ -4705,13 +5345,13 @@ void NormalMapNode::compile(SVMCompiler& compiler)
compiler.stack_assign(color_in),
compiler.stack_assign(strength_in),
compiler.stack_assign(normal_out),
- space_enum[space]),
+ space),
attr, attr_sign);
}
void NormalMapNode::compile(OSLCompiler& compiler)
{
- if(space == ustring("Tangent")) {
+ if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
@@ -4722,52 +5362,44 @@ void NormalMapNode::compile(OSLCompiler& compiler)
}
}
- compiler.parameter("space", space);
-
+ compiler.parameter(this, "space");
compiler.add(this, "node_normal_map");
}
/* Tangent */
-static ShaderEnum tangent_direction_type_init()
+NODE_DEFINE(TangentNode)
{
- ShaderEnum enm;
+ NodeType* type = NodeType::add("tangent", create, NodeType::SHADER);
- enm.insert("Radial", NODE_TANGENT_RADIAL);
- enm.insert("UV Map", NODE_TANGENT_UVMAP);
+ 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);
- return enm;
-}
+ 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 ShaderEnum tangent_axis_init()
-{
- ShaderEnum enm;
+ SOCKET_STRING(attribute, "Attribute", ustring(""));
- enm.insert("X", NODE_TANGENT_AXIS_X);
- enm.insert("Y", NODE_TANGENT_AXIS_Y);
- enm.insert("Z", NODE_TANGENT_AXIS_Z);
+ 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 enm;
+ return type;
}
-ShaderEnum TangentNode::direction_type_enum = tangent_direction_type_init();
-ShaderEnum TangentNode::axis_enum = tangent_axis_init();
-
TangentNode::TangentNode()
-: ShaderNode("tangent")
+: ShaderNode(node_type)
{
- direction_type = ustring("Radial");
- axis = ustring("X");
- attribute = ustring("");
-
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Tangent", SHADER_SOCKET_NORMAL);
}
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attributes->add(ATTR_STD_UV_TANGENT);
else
@@ -4785,7 +5417,7 @@ void TangentNode::compile(SVMCompiler& compiler)
ShaderOutput *tangent_out = output("Tangent");
int attr;
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
else
@@ -4797,21 +5429,21 @@ void TangentNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TANGENT,
compiler.encode_uchar4(
compiler.stack_assign(tangent_out),
- direction_type_enum[direction_type],
- axis_enum[axis]), attr);
+ direction_type,
+ axis), attr);
}
void TangentNode::compile(OSLCompiler& compiler)
{
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
compiler.parameter("attr_name", ustring("geom:tangent"));
else
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
}
- compiler.parameter("direction_type", direction_type);
- compiler.parameter("axis", axis);
+ compiler.parameter(this, "direction_type");
+ compiler.parameter(this, "axis");
compiler.add(this, "node_tangent");
}
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index c0f0dc29099..6c2467d9bee 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -18,6 +18,7 @@
#define __NODES_H__
#include "graph.h"
+#include "node.h"
#include "util_string.h"
@@ -35,6 +36,7 @@ public:
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);
@@ -49,48 +51,26 @@ public:
enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 };
Type type;
- static ShaderEnum type_enum;
enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 };
Mapping x_mapping, y_mapping, z_mapping;
- static ShaderEnum mapping_enum;
enum Projection { FLAT, CUBE, TUBE, SPHERE };
Projection projection;
- static ShaderEnum projection_enum;
-
- bool equals(const TextureMapping& other) {
- return translation == other.translation &&
- rotation == other.rotation &&
- scale == other.scale &&
- use_minmax == other.use_minmax &&
- min == other.min &&
- max == other.max &&
- type == other.type &&
- x_mapping == other.x_mapping &&
- y_mapping == other.y_mapping &&
- z_mapping == other.z_mapping &&
- projection == other.projection;
- }
};
/* Nodes */
class TextureNode : public ShaderNode {
public:
- explicit TextureNode(const char *name_) : ShaderNode(name_) {}
+ explicit TextureNode(const NodeType *node_type) : ShaderNode(node_type) {}
TextureMapping tex_mapping;
-
- virtual bool equals(const ShaderNode *other) {
- return ShaderNode::equals(other) &&
- tex_mapping.equals(((const TextureNode*)other)->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 char *name_) : TextureNode(name_) {
+ explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) {
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
}
int slot;
@@ -107,30 +87,22 @@ public:
int is_float;
bool is_linear;
bool use_alpha;
- string filename;
+ ustring filename;
void *builtin_data;
- ustring color_space;
- ustring projection;
+ NodeImageColorSpace color_space;
+ NodeImageProjection projection;
InterpolationType interpolation;
ExtensionType extension;
float projection_blend;
bool animated;
+ float3 vector;
- static ShaderEnum color_space_enum;
- static ShaderEnum projection_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const ImageTextureNode *image_node = (const ImageTextureNode*)other;
+ virtual bool equals(const ShaderNode& other)
+ {
+ const ImageTextureNode& image_node = (const ImageTextureNode&)other;
return ImageSlotTextureNode::equals(other) &&
- use_alpha == image_node->use_alpha &&
- filename == image_node->filename &&
- builtin_data == image_node->builtin_data &&
- color_space == image_node->color_space &&
- projection == image_node->projection &&
- interpolation == image_node->interpolation &&
- extension == image_node->extension &&
- projection_blend == image_node->projection_blend &&
- animated == image_node->animated;
+ builtin_data == image_node.builtin_data &&
+ animated == image_node.animated;
}
};
@@ -146,26 +118,20 @@ public:
int is_float;
bool is_linear;
bool use_alpha;
- string filename;
+ ustring filename;
void *builtin_data;
- ustring color_space;
- ustring projection;
+ NodeImageColorSpace color_space;
+ NodeEnvironmentProjection projection;
InterpolationType interpolation;
bool animated;
+ float3 vector;
- static ShaderEnum color_space_enum;
- static ShaderEnum projection_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other;
+ virtual bool equals(const ShaderNode& other)
+ {
+ const EnvironmentTextureNode& env_node = (const EnvironmentTextureNode&)other;
return ImageSlotTextureNode::equals(other) &&
- use_alpha == env_node->use_alpha &&
- filename == env_node->filename &&
- builtin_data == env_node->builtin_data &&
- color_space == env_node->color_space &&
- projection == env_node->projection &&
- interpolation == env_node->interpolation &&
- animated == env_node->animated;
+ builtin_data == env_node.builtin_data &&
+ animated == env_node.animated;
}
};
@@ -175,29 +141,24 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ NodeSkyType type;
float3 sun_direction;
float turbidity;
float ground_albedo;
-
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const SkyTextureNode *sky_node = (const SkyTextureNode*)other;
- return TextureNode::equals(other) &&
- sun_direction == sky_node->sun_direction &&
- turbidity == sky_node->turbidity &&
- ground_albedo == sky_node->ground_albedo &&
- type == sky_node->type;
- }
+ float3 vector;
};
class OutputNode : public ShaderNode {
public:
SHADER_NODE_CLASS(OutputNode)
+ void *surface;
+ void *volume;
+ float displacement;
+ float3 normal;
+
/* Don't allow output node de-duplication. */
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+ virtual bool equals(const ShaderNode& /*other*/) { return false; }
};
class GradientTextureNode : public TextureNode {
@@ -206,19 +167,16 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const GradientTextureNode *gradient_node = (const GradientTextureNode*)other;
- return TextureNode::equals(other) &&
- type == gradient_node->type;
- }
+ NodeGradientType type;
+ float3 vector;
};
class NoiseTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(NoiseTextureNode)
+
+ float scale, detail, distortion;
+ float3 vector;
};
class VoronoiTextureNode : public TextureNode {
@@ -227,15 +185,9 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring coloring;
-
- static ShaderEnum coloring_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other;
- return TextureNode::equals(other) &&
- coloring == voronoi_node->coloring;
- }
+ NodeVoronoiColoring coloring;
+ float scale;
+ float3 vector;
};
class MusgraveTextureNode : public TextureNode {
@@ -244,15 +196,9 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
-
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other;
- return TextureNode::equals(other) &&
- type == musgrave_node->type;
- }
+ NodeMusgraveType type;
+ float scale, detail, dimension, lacunarity, offset, gain;
+ float3 vector;
};
class WaveTextureNode : public TextureNode {
@@ -261,17 +207,11 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
- ustring profile;
- static ShaderEnum type_enum;
- static ShaderEnum profile_enum;
+ NodeWaveType type;
+ NodeWaveProfile profile;
- virtual bool equals(const ShaderNode *other) {
- const WaveTextureNode *wave_node = (const WaveTextureNode*)other;
- return TextureNode::equals(other) &&
- type == wave_node->type &&
- profile == wave_node->profile;
- }
+ float scale, distortion, detail, detail_scale;
+ float3 vector;
};
class MagicTextureNode : public TextureNode {
@@ -281,18 +221,17 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
int depth;
-
- virtual bool equals(const ShaderNode *other) {
- const MagicTextureNode *magic_node = (const MagicTextureNode*)other;
- return TextureNode::equals(other) &&
- depth == magic_node->depth;
- }
+ float3 vector;
+ float scale, distortion;
};
class CheckerTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(CheckerTextureNode)
+ float3 vector, color1, color2;
+ float scale;
+
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
@@ -303,16 +242,11 @@ public:
float offset, squash;
int offset_frequency, squash_frequency;
- virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ float3 color1, color2, mortar;
+ float scale, mortar_size, bias, brick_width, row_height;
+ float3 vector;
- virtual bool equals(const ShaderNode *other) {
- const BrickTextureNode *brick_node = (const BrickTextureNode*)other;
- return TextureNode::equals(other) &&
- offset == brick_node->offset &&
- squash == brick_node->squash &&
- offset_frequency == brick_node->offset_frequency &&
- squash_frequency == brick_node->squash_frequency;
- }
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
class PointDensityTextureNode : public ShaderNode {
@@ -326,25 +260,20 @@ public:
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return true; }
- ImageManager *image_manager;
- int slot;
- string filename;
- ustring space;
- void *builtin_data;
+ ustring filename;
+ NodeTexVoxelSpace space;
InterpolationType interpolation;
-
Transform tfm;
+ float3 vector;
- static ShaderEnum space_enum;
+ ImageManager *image_manager;
+ int slot;
+ void *builtin_data;
- virtual bool equals(const ShaderNode *other) {
- const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other;
+ virtual bool equals(const ShaderNode& other) {
+ const PointDensityTextureNode& point_dendity_node = (const PointDensityTextureNode&)other;
return ShaderNode::equals(other) &&
- filename == point_dendity_node->filename &&
- space == point_dendity_node->space &&
- builtin_data == point_dendity_node->builtin_data &&
- interpolation == point_dendity_node->interpolation &&
- tfm == point_dendity_node->tfm;
+ builtin_data == point_dendity_node.builtin_data;
}
};
@@ -353,46 +282,60 @@ public:
SHADER_NODE_CLASS(MappingNode)
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ float3 vector;
TextureMapping tex_mapping;
+};
- virtual bool equals(const ShaderNode *other) {
- const MappingNode *mapping_node = (const MappingNode*)other;
- return ShaderNode::equals(other) &&
- tex_mapping.equals(mapping_node->tex_mapping);
- }
+class RGBToBWNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(RGBToBWNode)
+ void constant_fold(const ConstantFolder& folder);
+
+ float3 color;
};
class ConvertNode : public ShaderNode {
public:
- ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false);
+ ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false);
SHADER_NODE_BASE_CLASS(ConvertNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
- ShaderSocketType from, to;
+ SocketType::Type from, to;
- virtual bool equals(const ShaderNode *other)
- {
- const ConvertNode *convert_node = (const ConvertNode*)other;
- return ShaderNode::equals(other) &&
- from == convert_node->from &&
- to == convert_node->to;
- }
+ 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;
};
class BsdfNode : public ShaderNode {
public:
- explicit BsdfNode(bool scattering = false);
+ explicit BsdfNode(const NodeType *node_type);
SHADER_NODE_BASE_CLASS(BsdfNode);
bool has_spatial_varying() { return true; }
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL);
virtual ClosureType get_closure_type() { return closure; }
+ float3 color;
+ float3 normal;
+ float surface_mix_weight;
ClosureType closure;
- bool scattering;
- virtual bool equals(const ShaderNode * /*other*/)
+ virtual bool equals(const ShaderNode& /*other*/)
{
/* TODO(sergey): With some care BSDF nodes can be de-duplicated. */
return false;
@@ -403,15 +346,19 @@ class AnisotropicBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(AnisotropicBsdfNode)
- ustring distribution;
- static ShaderEnum distribution_enum;
+ float3 tangent;
+ float roughness, anisotropy, rotation;
+ ClosureType distribution;
+ ClosureType get_closure_type() { return distribution; }
void attributes(Shader *shader, AttributeRequestSet *attributes);
};
class DiffuseBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(DiffuseBsdfNode)
+
+ float roughness;
};
/* Disney BRDF */
@@ -427,6 +374,12 @@ public:
ShaderInput *sheen, ShaderInput *sheenTint, ShaderInput *clearcoat, ShaderInput *clearcoatGloss,
ShaderInput *ior, ShaderInput *transparency, ShaderInput *refr_roughness);
+ float3 base_color;
+ float3 subsurface_color;
+ float metallic, subsurface, specular, roughness, specularTint, anisotropic,
+ sheen, sheenTint, clearcoat, clearcoatGloss, ior, transparency, refractionRoughness;
+ float3 normal, clearcoatNormal, tangent;
+ float surface_mix_weight;
ClosureType closure;
virtual bool equals(const ShaderNode * /*other*/)
@@ -451,6 +404,8 @@ public:
class VelvetBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(VelvetBsdfNode)
+
+ float sigma;
};
class GlossyBsdfNode : public BsdfNode {
@@ -459,9 +414,10 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
+ ClosureType get_closure_type() { return distribution; }
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ float roughness;
+ ClosureType distribution, distribution_orig;
};
class GlassBsdfNode : public BsdfNode {
@@ -470,9 +426,10 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
+ ClosureType get_closure_type() { return distribution; }
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ float roughness, IOR;
+ ClosureType distribution, distribution_orig;
};
class RefractionBsdfNode : public BsdfNode {
@@ -481,17 +438,18 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
+ ClosureType get_closure_type() { return distribution; }
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ float roughness, IOR;
+ ClosureType distribution, distribution_orig;
};
class ToonBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(ToonBsdfNode)
- ustring component;
- static ShaderEnum component_enum;
+ float smooth, size;
+ ClosureType component;
};
class SubsurfaceScatteringNode : public BsdfNode {
@@ -499,24 +457,37 @@ public:
SHADER_NODE_CLASS(SubsurfaceScatteringNode)
bool has_surface_bssrdf() { return true; }
bool has_bssrdf_bump();
+ ClosureType get_closure_type() { return falloff; }
- static ShaderEnum falloff_enum;
+ float scale;
+ float3 radius;
+ float sharpness;
+ float texture_blur;
+ ClosureType falloff;
};
class EmissionNode : public ShaderNode {
public:
SHADER_NODE_CLASS(EmissionNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; }
bool has_surface_emission() { return true; }
+
+ float3 color;
+ float strength;
+ float surface_mix_weight;
};
class BackgroundNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BackgroundNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; }
+
+ float3 color;
+ float strength;
+ float surface_mix_weight;
};
class HoldoutNode : public ShaderNode {
@@ -524,6 +495,9 @@ 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;
};
class AmbientOcclusionNode : public ShaderNode {
@@ -533,11 +507,16 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
virtual ClosureType get_closure_type() { return CLOSURE_AMBIENT_OCCLUSION_ID; }
+
+ float3 normal_osl;
+ float3 color;
+ float surface_mix_weight;
};
class VolumeNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(VolumeNode)
+ 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; }
@@ -546,9 +525,12 @@ public:
}
virtual ClosureType get_closure_type() { return closure; }
+ float3 color;
+ float density;
+ float volume_mix_weight;
ClosureType closure;
- virtual bool equals(const ShaderNode * /*other*/)
+ virtual bool equals(const ShaderNode& /*other*/)
{
/* TODO(sergey): With some care Volume nodes can be de-duplicated. */
return false;
@@ -563,15 +545,20 @@ public:
class ScatterVolumeNode : public VolumeNode {
public:
SHADER_NODE_CLASS(ScatterVolumeNode)
+
+ float anisotropy;
};
class HairBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(HairBsdfNode)
+ ClosureType get_closure_type() { return component; }
- ustring component;
- static ShaderEnum component_enum;
-
+ ClosureType component;
+ float offset;
+ float roughness_u;
+ float roughness_v;
+ float3 tangent;
};
class GeometryNode : public ShaderNode {
@@ -579,6 +566,8 @@ public:
SHADER_NODE_CLASS(GeometryNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_spatial_varying() { return true; }
+
+ float3 normal_osl;
};
class TextureCoordinateNode : public ShaderNode {
@@ -588,17 +577,10 @@ public:
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;
-
- virtual bool equals(const ShaderNode *other) {
- const TextureCoordinateNode *texco_node = (const TextureCoordinateNode*)other;
- return ShaderNode::equals(other) &&
- from_dupli == texco_node->from_dupli &&
- use_transform == texco_node->use_transform &&
- ob_tfm == texco_node->ob_tfm;
- }
};
class UVMapNode : public ShaderNode {
@@ -610,13 +592,6 @@ public:
ustring attribute;
bool from_dupli;
-
- virtual bool equals(const ShaderNode *other) {
- const UVMapNode *uv_map_node = (const UVMapNode*)other;
- return ShaderNode::equals(other) &&
- attribute == uv_map_node->attribute &&
- from_dupli == uv_map_node->from_dupli;
- }
};
class LightPathNode : public ShaderNode {
@@ -630,6 +605,9 @@ public:
SHADER_NODE_CLASS(LightFalloffNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
+ float strength;
+ float smooth;
};
class ObjectInfoNode : public ShaderNode {
@@ -661,136 +639,150 @@ class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
float value;
-
- virtual bool equals(const ShaderNode *other) {
- const ValueNode *value_node = (const ValueNode*)other;
- return ShaderNode::equals(other) &&
- value == value_node->value;
- }
};
class ColorNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ColorNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
float3 value;
-
- virtual bool equals(const ShaderNode *other) {
- const ColorNode *color_node = (const ColorNode*)other;
- return ShaderNode::equals(other) &&
- value == color_node->value;
- }
};
class AddClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(AddClosureNode)
+ void constant_fold(const ConstantFolder& folder);
};
class MixClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixClosureNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
+
+ float fac;
};
class MixClosureWeightNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixClosureWeightNode);
+
+ 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; }
+
+ float fac;
+ float3 color;
};
class MixNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+ NodeMix type;
bool use_clamp;
-
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other)
- {
- const MixNode *mix_node = (const MixNode*)other;
- return ShaderNode::equals(other) &&
- use_clamp == mix_node->use_clamp &&
- type == mix_node->type;
- }
+ 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; }
+
+ 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; }
+
+ 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; }
+
+ float x, y, z;
};
class GammaNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GammaNode)
-
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ 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; }
+
+ 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; }
+
+ 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; }
+
+ 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; }
+
+ float3 vector;
};
class HSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(HSVNode)
+
+ float hue;
+ float saturation;
+ float value;
+ float fac;
+ float3 color;
};
class AttributeNode : public ShaderNode {
@@ -800,12 +792,6 @@ public:
bool has_spatial_varying() { return true; }
ustring attribute;
-
- virtual bool equals(const ShaderNode *other) {
- const AttributeNode *color_node = (const AttributeNode*)other;
- return ShaderNode::equals(other) &&
- attribute == color_node->attribute;
- }
};
class CameraNode : public ShaderNode {
@@ -819,6 +805,9 @@ public:
SHADER_NODE_CLASS(FresnelNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ float3 normal;
+ float IOR;
};
class LayerWeightNode : public ShaderNode {
@@ -826,6 +815,9 @@ public:
SHADER_NODE_CLASS(LayerWeightNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+
+ float3 normal;
+ float blend;
};
class WireframeNode : public ShaderNode {
@@ -834,42 +826,37 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+ float size;
bool use_pixel_size;
};
class WavelengthNode : public ShaderNode {
public:
SHADER_NODE_CLASS(WavelengthNode)
-
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float wavelength;
};
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
-
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+
+ float temperature;
};
class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
+ float value1;
+ float value2;
+ NodeMath type;
bool use_clamp;
-
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other)
- {
- const MathNode *math_node = (const MathNode*)other;
- return ShaderNode::equals(other) &&
- use_clamp == math_node->use_clamp &&
- type == math_node->type;
- }
};
class NormalNode : public ShaderNode {
@@ -878,30 +865,18 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
float3 direction;
-
- virtual bool equals(const ShaderNode *other)
- {
- const NormalNode *normal_node = (const NormalNode*)other;
- return ShaderNode::equals(other) &&
- direction == normal_node->direction;
- }
+ float3 normal;
};
class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
- ustring type;
- static ShaderEnum type_enum;
-
- virtual bool equals(const ShaderNode *other)
- {
- const MathNode *math_node = (const MathNode*)other;
- return ShaderNode::equals(other) &&
- type == math_node->type;
- }
+ float3 vector1;
+ float3 vector2;
+ NodeVectorMath type;
};
class VectorTransformNode : public ShaderNode {
@@ -910,88 +885,97 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring type;
- ustring convert_from;
- ustring convert_to;
-
- static ShaderEnum type_enum;
- static ShaderEnum convert_space_enum;
-
- virtual bool equals(const ShaderNode *other) {
- const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other;
- return ShaderNode::equals(other) &&
- type == vector_transform_node->type &&
- convert_from == vector_transform_node->convert_from &&
- convert_to == vector_transform_node->convert_to;
- }
+ NodeVectorTransformType type;
+ NodeVectorTransformConvertSpace convert_from;
+ NodeVectorTransformConvertSpace convert_to;
+ float3 vector;
};
class BumpNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BumpNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ void constant_fold(const ConstantFolder& folder);
bool has_spatial_varying() { return true; }
virtual int get_feature() {
return NODE_FEATURE_BUMP;
}
bool invert;
-
- virtual bool equals(const ShaderNode *other) {
- const BumpNode *bump_node = (const BumpNode*)other;
- return ShaderNode::equals(other) &&
- invert == bump_node->invert;
- }
+ float height;
+ float sample_center;
+ float sample_x;
+ float sample_y;
+ float3 normal;
+ float strength;
+ float distance;
};
-class RGBCurvesNode : public ShaderNode {
+class CurvesNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(RGBCurvesNode)
+ explicit CurvesNode(const NodeType *node_type);
+ SHADER_NODE_BASE_CLASS(CurvesNode);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
array<float3> curves;
- float min_x, max_x;
+ float min_x, max_x, fac;
+ float3 value;
+
+protected:
+ 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 VectorCurvesNode : public ShaderNode {
+class RGBCurvesNode : public CurvesNode {
public:
- SHADER_NODE_CLASS(VectorCurvesNode)
-
- virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+ SHADER_NODE_CLASS(RGBCurvesNode)
+ void constant_fold(const ConstantFolder& folder);
+};
- array<float3> curves;
- float min_x, max_x;
+class VectorCurvesNode : public CurvesNode {
+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; }
+
array<float3> ramp;
array<float> ramp_alpha;
+ float fac;
bool interpolate;
- virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
};
class SetNormalNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SetNormalNode)
+ float3 direction;
};
-class OSLScriptNode : public ShaderNode {
+class OSLNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(OSLScriptNode)
+ static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL);
+ ~OSLNode();
+
+ ShaderNode *clone() const;
+
+ 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)
/* ideally we could beter detect this, but we can't query this now */
bool has_spatial_varying() { return true; }
+ virtual bool equals(const ShaderNode& /*other*/) { return false; }
string filepath;
string bytecode_hash;
-
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
};
class NormalMapNode : public ShaderNode {
@@ -1001,18 +985,11 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring space;
- static ShaderEnum space_enum;
-
+ NodeNormalMapSpace space;
ustring attribute;
-
- virtual bool equals(const ShaderNode *other)
- {
- const NormalMapNode *normal_map_node = (const NormalMapNode*)other;
- return ShaderNode::equals(other) &&
- space == normal_map_node->space &&
- attribute == normal_map_node->attribute;
- }
+ float strength;
+ float3 color;
+ float3 normal_osl;
};
class TangentNode : public ShaderNode {
@@ -1022,22 +999,10 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring direction_type;
- static ShaderEnum direction_type_enum;
-
- ustring axis;
- static ShaderEnum axis_enum;
-
+ NodeTangentDirectionType direction_type;
+ NodeTangentAxis axis;
ustring attribute;
-
- virtual bool equals(const ShaderNode *other)
- {
- const TangentNode *tangent_node = (const TangentNode*)other;
- return ShaderNode::equals(other) &&
- direction_type == tangent_node->direction_type &&
- axis == tangent_node->axis &&
- attribute == tangent_node->attribute;
- }
+ float3 normal_osl;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index e2fe0bd72a1..662d87e8b6b 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -33,14 +33,25 @@ CCL_NAMESPACE_BEGIN
/* 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_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));
+
+ return type;
+}
+
Object::Object()
+: Node(node_type)
{
- name = "";
- mesh = NULL;
- tfm = transform_identity();
- visibility = ~0;
- random_id = 0;
- pass_id = 0;
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
@@ -48,9 +59,6 @@ Object::Object()
motion.mid = transform_identity();
motion.post = transform_identity();
use_motion = false;
- use_holdout = false;
- dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
- dupli_uv = make_float2(0.0f, 0.0f);
}
Object::~Object()
@@ -137,12 +145,12 @@ void Object::apply_transform(bool apply_to_motion)
/* apply transform to curve keys */
for(size_t i = 0; i < mesh->curve_keys.size(); i++) {
- float3 co = transform_point(&tfm, float4_to_float3(mesh->curve_keys[i]));
- float radius = mesh->curve_keys[i].w * scalar;
+ 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] = float3_to_float4(co);
- mesh->curve_keys[i].w = radius;
+ mesh->curve_keys[i] = co;
+ mesh->curve_radius[i] = radius;
}
if(apply_to_motion) {
@@ -176,7 +184,7 @@ void Object::apply_transform(bool apply_to_motion)
}
/* tfm is not reset to identity, all code that uses it needs to check the
- transform_applied boolean */
+ * transform_applied boolean */
}
void Object::tag_update(Scene *scene)
@@ -217,6 +225,16 @@ vector<float> Object::motion_times()
return times;
}
+bool Object::is_traceable()
+{
+ /* Mesh itself can be empty,can skip all such objects. */
+ if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
+ return false;
+ }
+ /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
+ return true;
+}
+
/* Object Manager */
ObjectManager::ObjectManager()
@@ -269,7 +287,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
state->surface_area_lock.unlock();
if(it == state->surface_area_map.end()) {
- foreach(Mesh::Triangle& t, mesh->triangles) {
+ 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]];
@@ -288,7 +308,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
surface_area *= uniform_scale;
}
else {
- foreach(Mesh::Triangle& t, mesh->triangles) {
+ 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]]);
@@ -360,7 +382,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
state->object_flag[object_index] = flag;
/* Have curves. */
- if(mesh->curves.size()) {
+ if(mesh->num_curves()) {
state->have_curves = true;
}
}
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index c2a79ca8dc4..7ab73f3c91a 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -17,6 +17,7 @@
#ifndef __OBJECT_H__
#define __OBJECT_H__
+#include "node.h"
#include "scene.h"
#include "util_boundbox.h"
@@ -37,12 +38,13 @@ struct Transform;
/* Object */
-class Object {
+class Object : public Node {
public:
+ NODE_DECLARE;
+
Mesh *mesh;
Transform tfm;
BoundBox bounds;
- ustring name;
uint random_id;
int pass_id;
vector<ParamValue> attributes;
@@ -66,6 +68,11 @@ public:
void apply_transform(bool apply_to_motion);
vector<float> motion_times();
+
+ /* Check whether object is traceable and it worth adding it to
+ * kernel scene.
+ */
+ bool is_traceable();
};
/* Object Manager */
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 3d14965b4ca..676afad997e 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -394,16 +394,145 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
{
ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
- /* this is a bit weak, but works */
OSLShaderInfo info;
+
+ 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);
+
loaded_shaders[hash] = info;
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)
+{
+ /* 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_, ImageManager *image_manager_)
@@ -427,7 +556,7 @@ string OSLCompiler::id(ShaderNode *node)
string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
{
- string sname(input->name);
+ string sname(input->name().string());
size_t i;
/* strip whitespace */
@@ -436,7 +565,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
/* if output exists with the same name, add "In" suffix */
foreach(ShaderOutput *output, node->outputs) {
- if(strcmp(input->name, output->name)==0) {
+ if(input->name() == output->name()) {
sname += "In";
break;
}
@@ -447,7 +576,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
{
- string sname(output->name);
+ string sname(output->name().string());
size_t i;
/* strip whitespace */
@@ -456,7 +585,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
/* if input exists with the same name, add "Out" suffix */
foreach(ShaderInput *input, node->inputs) {
- if(strcmp(input->name, output->name)==0) {
+ if(input->name() == output->name()) {
sname += "Out";
break;
}
@@ -470,21 +599,21 @@ 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->usage & ShaderInput::USE_OSL))
+ if(input->flags() & SocketType::SVM_INTERNAL)
return true;
if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
- if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE)
+ if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE)
return true;
- if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME)
+ if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME)
return true;
- if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT)
+ if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
return true;
- if(strcmp(input->name, "Normal") == 0)
+ if(input->name() == "Normal")
return true;
}
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
- if(strcmp(input->name, "Height") == 0)
+ if(input->name() == "Height")
return true;
}
else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
@@ -512,34 +641,36 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
if(node_skip_input(node, input))
continue;
/* already has default value assigned */
- else if(input->default_value != ShaderInput::NONE)
+ else if(input->flags() & SocketType::DEFAULT_LINK_MASK)
continue;
string param_name = compatible_name(node, input);
- switch(input->type) {
- case SHADER_SOCKET_COLOR:
- parameter_color(param_name.c_str(), input->value);
+ const SocketType& socket = input->socket_type;
+ switch(input->type()) {
+ case SocketType::COLOR:
+ parameter_color(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_POINT:
- parameter_point(param_name.c_str(), input->value);
+ case SocketType::POINT:
+ parameter_point(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_VECTOR:
- parameter_vector(param_name.c_str(), input->value);
+ case SocketType::VECTOR:
+ parameter_vector(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_NORMAL:
- parameter_normal(param_name.c_str(), input->value);
+ case SocketType::NORMAL:
+ parameter_normal(param_name.c_str(), node->get_float3(socket));
break;
- case SHADER_SOCKET_FLOAT:
- parameter(param_name.c_str(), input->value.x);
+ case SocketType::FLOAT:
+ parameter(param_name.c_str(), node->get_float(socket));
break;
- case SHADER_SOCKET_INT:
- parameter(param_name.c_str(), (int)input->value.x);
+ case SocketType::INT:
+ parameter(param_name.c_str(), node->get_int(socket));
break;
- case SHADER_SOCKET_STRING:
- parameter(param_name.c_str(), input->value_string);
+ case SocketType::STRING:
+ parameter(param_name.c_str(), node->get_string(socket));
break;
- case SHADER_SOCKET_CLOSURE:
- case SHADER_SOCKET_UNDEFINED:
+ case SocketType::CLOSURE:
+ case SocketType::UNDEFINED:
+ default:
break;
}
}
@@ -605,6 +736,169 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
}
}
+static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
+{
+ return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
+ (TypeDesc::AGGREGATE)typedesc.aggregate,
+ (TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
+ arraylength);
+}
+
+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);
+ ss->Parameter(uname, TypeDesc::TypeMatrix, &value);
+ 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);
+ ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, value.size()), value.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;
@@ -868,6 +1162,10 @@ void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfil
{
}
+void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/)
+{
+}
+
void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
{
}
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 110897ff300..b131b672b8c 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -22,6 +22,7 @@
#include "util_thread.h"
#include "graph.h"
+#include "nodes.h"
#include "shader.h"
#ifdef WITH_OSL
@@ -54,6 +55,7 @@ struct OSLShaderInfo {
has_surface_bssrdf(false)
{}
+ OSL::OSLQuery query;
bool has_surface_emission;
bool has_surface_transparent;
bool has_surface_bssrdf;
@@ -83,6 +85,11 @@ public:
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();
@@ -118,6 +125,8 @@ public:
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);
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index 50726bb4574..1a35d60fb4b 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -58,8 +58,8 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
* 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;
- foreach(ParticleSystem *psys, scene->particle_systems)
- num_particles += psys->particles.size();
+ for(size_t j = 0; j < scene->particle_systems.size(); j++)
+ num_particles += scene->particle_systems[j]->particles.size();
float4 *particles = dscene->particles.resize(PARTICLE_SIZE*num_particles);
@@ -71,9 +71,12 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
int i = 1;
- foreach(ParticleSystem *psys, scene->particle_systems) {
- foreach(Particle &pa, psys->particles) {
+ 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];
int offset = i*PARTICLE_SIZE;
particles[offset] = make_float4(pa.index, pa.age, pa.lifetime, pa.size);
diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h
index bf2b6b77015..2509e27b44b 100644
--- a/intern/cycles/render/particles.h
+++ b/intern/cycles/render/particles.h
@@ -47,7 +47,7 @@ public:
void tag_update(Scene *scene);
- vector<Particle> particles;
+ array<Particle> particles;
};
/* ParticleSystem Manager */
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index b0052c30af4..b341837b7e8 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -242,9 +242,14 @@ void Scene::device_update(Device *device_, Progress& progress)
}
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: " << util_guarded_get_mem_used() << "\n"
- << " Peak: " << util_guarded_get_mem_peak();
+ << " 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) << ")";
}
}
@@ -258,6 +263,14 @@ Scene::MotionType Scene::need_motion(bool advanced_shading)
return MOTION_NONE;
}
+float Scene::motion_shutter_time()
+{
+ 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)
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 33c03d40f27..9e72f197cce 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -63,7 +63,8 @@ public:
device_vector<float4> bvh_nodes;
device_vector<float4> bvh_leaf_nodes;
device_vector<uint> object_node;
- device_vector<float4> tri_storage;
+ device_vector<uint> prim_tri_index;
+ device_vector<float4> prim_tri_verts;
device_vector<uint> prim_type;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
@@ -72,12 +73,15 @@ public:
/* mesh */
device_vector<uint> tri_shader;
device_vector<float4> tri_vnormal;
- device_vector<float4> tri_vindex;
- device_vector<float4> tri_verts;
+ 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<float4> objects;
device_vector<float4> objects_vector;
@@ -109,10 +113,12 @@ public:
device_vector<uint> sobol_directions;
/* cpu images */
- device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_IMAGES_CPU];
- device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_IMAGES_CPU];
- device_vector<float> tex_float_image[TEX_NUM_FLOAT_IMAGES_CPU];
- device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_IMAGES_CPU];
+ device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_CPU];
+ device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU];
+ device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU];
+ device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU];
+ device_vector<half4> tex_half4_image[TEX_NUM_HALF4_CPU];
+ device_vector<half> tex_half_image[TEX_NUM_HALF_CPU];
/* opencl images */
device_vector<uchar4> tex_image_byte4_packed;
@@ -134,6 +140,7 @@ public:
BVH_NUM_TYPES,
} bvh_type;
bool use_bvh_spatial_split;
+ bool use_bvh_unaligned_nodes;
bool use_qbvh;
bool persistent_data;
@@ -142,6 +149,7 @@ public:
shadingsystem = SHADINGSYSTEM_SVM;
bvh_type = BVH_DYNAMIC;
use_bvh_spatial_split = false;
+ use_bvh_unaligned_nodes = true;
use_qbvh = false;
persistent_data = false;
}
@@ -150,6 +158,7 @@ public:
{ return !(shadingsystem == params.shadingsystem
&& bvh_type == params.bvh_type
&& use_bvh_spatial_split == params.use_bvh_spatial_split
+ && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); }
};
@@ -208,6 +217,7 @@ public:
enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
MotionType need_motion(bool advanced_shading = true);
+ float motion_shutter_time();
bool need_update();
bool need_reset();
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 76979e9ba3e..1cd76ff2b39 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -630,7 +630,7 @@ DeviceRequestedFeatures Session::get_requested_device_features()
requested_features.use_camera_motion = scene->camera->use_motion;
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
- if(mesh->curves.size() > 0) {
+ if(mesh->num_curves()) {
requested_features.use_hair = true;
}
requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 635024d7bdf..4cdb878df45 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -449,17 +449,15 @@ void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scen
void ShaderManager::add_default(Scene *scene)
{
- ShaderNode *closure, *out;
-
/* default surface */
{
ShaderGraph *graph = new ShaderGraph();
- closure = graph->add(new DiffuseBsdfNode());
- closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f);
- out = graph->output();
+ DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
+ diffuse->color = make_float3(0.8f, 0.8f, 0.8f);
+ graph->add(diffuse);
- graph->connect(closure->output("BSDF"), out->input("Surface"));
+ graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
Shader *shader = new Shader();
shader->name = "default_surface";
@@ -472,12 +470,12 @@ void ShaderManager::add_default(Scene *scene)
{
ShaderGraph *graph = new ShaderGraph();
- closure = graph->add(new EmissionNode());
- closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f);
- closure->input("Strength")->value.x = 0.0f;
- out = graph->output();
+ EmissionNode *emission = new EmissionNode();
+ emission->color = make_float3(0.8f, 0.8f, 0.8f);
+ emission->strength = 0.0f;
+ graph->add(emission);
- graph->connect(closure->output("Emission"), out->input("Surface"));
+ graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
Shader *shader = new Shader();
shader->name = "default_light";
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 4c97a5ad792..1a166885e2b 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -65,20 +65,21 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
}
-
+
foreach(Shader *shader, scene->shaders) {
if(progress.get_cancel()) return;
assert(shader->graph);
- if(shader->use_mis && shader->has_surface_emission)
- scene->light_manager->need_update = true;
-
SVMCompiler::Summary summary;
SVMCompiler compiler(scene->shader_manager, scene->image_manager);
compiler.background = (shader == scene->default_background);
compiler.compile(scene, shader, svm_nodes, shader->id, &summary);
+ if(shader->use_mis && shader->has_surface_emission) {
+ scene->light_manager->need_update = true;
+ }
+
VLOG(2) << "Compilation summary:\n"
<< "Shader name: " << shader->name << "\n"
<< summary.full_report();
@@ -120,22 +121,22 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_man
compile_failed = false;
}
-int SVMCompiler::stack_size(ShaderSocketType type)
+int SVMCompiler::stack_size(SocketType::Type type)
{
int size = 0;
switch(type) {
- case SHADER_SOCKET_FLOAT:
- case SHADER_SOCKET_INT:
+ case SocketType::FLOAT:
+ case SocketType::INT:
size = 1;
break;
- case SHADER_SOCKET_COLOR:
- case SHADER_SOCKET_VECTOR:
- case SHADER_SOCKET_NORMAL:
- case SHADER_SOCKET_POINT:
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::NORMAL:
+ case SocketType::POINT:
size = 3;
break;
- case SHADER_SOCKET_CLOSURE:
+ case SocketType::CLOSURE:
size = 0;
break;
default:
@@ -146,7 +147,7 @@ int SVMCompiler::stack_size(ShaderSocketType type)
return size;
}
-int SVMCompiler::stack_find_offset(ShaderSocketType type)
+int SVMCompiler::stack_find_offset(SocketType::Type type)
{
int size = stack_size(type);
int offset = -1;
@@ -175,7 +176,7 @@ int SVMCompiler::stack_find_offset(ShaderSocketType type)
return 0;
}
-void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset)
+void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
{
int size = stack_size(type);
@@ -192,23 +193,25 @@ int SVMCompiler::stack_assign(ShaderInput *input)
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);
+ input->stack_offset = stack_find_offset(input->type());
- if(input->type == SHADER_SOCKET_FLOAT) {
- add_node(NODE_VALUE_F, __float_as_int(input->value.x), input->stack_offset);
+ 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 == SHADER_SOCKET_INT) {
- add_node(NODE_VALUE_F, (int)input->value.x, 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 == SHADER_SOCKET_VECTOR ||
- input->type == SHADER_SOCKET_NORMAL ||
- input->type == SHADER_SOCKET_POINT ||
- input->type == SHADER_SOCKET_COLOR)
+ 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, input->value);
+ add_node(NODE_VALUE_V, node->get_float3(input->socket_type));
}
else /* should not get called for closure */
assert(0);
@@ -222,7 +225,7 @@ 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);
+ output->stack_offset = stack_find_offset(output->type());
return output->stack_offset;
}
@@ -247,11 +250,11 @@ 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));
+ assert(stack_size(output->type()) == stack_size(input->link->type()));
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]++;
@@ -279,7 +282,7 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done)
all_done = false;
if(all_done) {
- stack_clear_offset(output->type, output->stack_offset);
+ stack_clear_offset(output->type(), output->stack_offset);
output->stack_offset = SVM_STACK_INVALID;
foreach(ShaderInput *in, output->links)
@@ -293,7 +296,7 @@ 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);
+ stack_clear_offset(input->type(), input->stack_offset);
input->stack_offset = SVM_STACK_INVALID;
}
}
@@ -446,7 +449,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node,
const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight";
ShaderInput *weight_in = node->input(weight_name);
- if(weight_in && (weight_in->link || weight_in->value.x != 1.0f))
+ 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;
@@ -479,7 +482,7 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
}
else {
foreach(ShaderInput *in, node->inputs) {
- if(in->type == SHADER_SOCKET_CLOSURE && in->link)
+ if(in->type() == SocketType::CLOSURE && in->link)
generated_shared_closure_nodes(root_node,
in->link->parent,
state,
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index dbf1b1de947..e14d57d7601 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -99,8 +99,8 @@ public:
int stack_assign(ShaderInput *input);
int stack_assign_if_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderOutput *output);
- int stack_find_offset(ShaderSocketType type);
- void stack_clear_offset(ShaderSocketType type, int offset);
+ 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);
@@ -172,7 +172,7 @@ protected:
};
void stack_clear_temporary(ShaderNode *node);
- int stack_size(ShaderSocketType type);
+ int stack_size(SocketType::Type type);
void stack_clear_users(ShaderNode *node, ShaderNodeSet& done);
bool node_skip_input(ShaderNode *node, ShaderInput *input);