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:
Diffstat (limited to 'intern/cycles/kernel/osl/osl_services.cpp')
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
new file mode 100644
index 00000000000..ded3a68d667
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "osl_services.h"
+#include "osl_shader.h"
+
+#include "util_foreach.h"
+#include "util_string.h"
+
+#include "kernel_compat_cpu.h"
+#include "kernel_globals.h"
+#include "kernel_object.h"
+#include "kernel_triangle.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* RenderServices implementation */
+
+#define TO_MATRIX44(m) (*(OSL::Matrix44*)&(m))
+
+/* static ustrings */
+ustring OSLRenderServices::u_distance("distance");
+ustring OSLRenderServices::u_index("index");
+ustring OSLRenderServices::u_camera("camera");
+ustring OSLRenderServices::u_screen("screen");
+ustring OSLRenderServices::u_raster("raster");
+ustring OSLRenderServices::u_ndc("NDC");
+ustring OSLRenderServices::u_empty;
+
+OSLRenderServices::OSLRenderServices()
+{
+ kernel_globals = NULL;
+}
+
+OSLRenderServices::~OSLRenderServices()
+{
+}
+
+void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_)
+{
+ kernel_globals = kernel_globals_;
+}
+
+bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
+{
+ /* this is only used for shader and object space, we don't really have
+ a concept of shader space, so we just use object space for both. */
+ if(xform) {
+ KernelGlobals *kg = kernel_globals;
+ const ShaderData *sd = (const ShaderData*)xform;
+ int object = sd->object;
+
+ if(object != ~0) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ tfm = transform_transpose(tfm);
+ result = TO_MATRIX44(tfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
+{
+ /* this is only used for shader and object space, we don't really have
+ a concept of shader space, so we just use object space for both. */
+ if(xform) {
+ KernelGlobals *kg = kernel_globals;
+ const ShaderData *sd = (const ShaderData*)xform;
+ int object = sd->object;
+
+ if(object != ~0) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ tfm = transform_transpose(tfm);
+ result = TO_MATRIX44(tfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time)
+{
+ KernelGlobals *kg = kernel_globals;
+
+ if(from == u_ndc) {
+ Transform tfm = transform_transpose(kernel_data.cam.ndctoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(from == u_raster) {
+ Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(from == u_screen) {
+ Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(from == u_camera) {
+ Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time)
+{
+ KernelGlobals *kg = kernel_globals;
+
+ if(to == u_ndc) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(to == u_raster) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(to == u_screen) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(to == u_camera) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives,
+ ustring object, TypeDesc type, ustring name,
+ int index, void *val)
+{
+ return false;
+}
+
+static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd,
+ const OSLGlobals::Attribute& attr, bool derivatives, void *val)
+{
+ if(attr.type == TypeDesc::TypeFloat) {
+ float *fval = (float*)val;
+ fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
+ (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL);
+ }
+ else {
+ float3 *fval = (float3*)val;
+ fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
+ (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL);
+ }
+
+ return true;
+}
+
+static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd,
+ const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val)
+{
+ if(attr.type == TypeDesc::TypeFloat) {
+ float tmp[3];
+ float3 *fval = (float3*)val;
+
+ get_mesh_attribute(kg, sd, attr, derivatives, tmp);
+
+ fval[0] = make_float3(tmp[0], tmp[0], tmp[0]);
+ if(derivatives) {
+ fval[1] = make_float3(tmp[1], tmp[1], tmp[1]);
+ fval[2] = make_float3(tmp[2], tmp[2], tmp[2]);
+ }
+
+ return true;
+ }
+ else if(attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
+ attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
+ float3 tmp[3];
+ float *fval = (float*)val;
+
+ get_mesh_attribute(kg, sd, attr, derivatives, tmp);
+
+ fval[0] = average(tmp[0]);
+ if(derivatives) {
+ fval[1] = average(tmp[1]);
+ fval[2] = average(tmp[2]);
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
+{
+ size_t datasize = attr.value.datasize();
+
+ memcpy(val, attr.value.data(), datasize);
+ if(derivatives)
+ memset((char*)val + datasize, 0, datasize*2);
+}
+
+bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
+ TypeDesc type, ustring name, void *val)
+{
+ KernelGlobals *kg = kernel_globals;
+ const ShaderData *sd = (const ShaderData*)renderstate;
+ int object = sd->object;
+ int tri = sd->prim;
+
+ /* lookup of attribute on another object */
+ if(object_name != u_empty) {
+ OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
+
+ if(it == kg->osl.object_name_map.end())
+ return false;
+
+ object = it->second;
+ tri = ~0;
+ }
+ else if(object == ~0) {
+ /* no background attributes supported */
+ return false;
+ }
+
+ /* find attribute on object */
+ OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
+ OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
+
+ if(it == attribute_map.end())
+ return false;
+
+ /* type mistmatch? */
+ const OSLGlobals::Attribute& attr = it->second;
+
+ if(attr.elem != ATTR_ELEMENT_VALUE) {
+ /* triangle and vertex attributes */
+ if(tri != ~0) {
+ if(attr.type == type || (attr.type == TypeDesc::TypeColor &&
+ (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal)))
+ return get_mesh_attribute(kg, sd, attr, derivatives, val);
+ else
+ return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val);
+ }
+ }
+ else {
+ /* object attribute */
+ get_object_attribute(attr, derivatives, val);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type,
+ void *renderstate, void *val)
+{
+ return false; /* disabled by lockgeom */
+}
+
+bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
+{
+ return false; /* never called by OSL */
+}
+
+void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names,
+ TypeDesc *attr_types, int nattrs)
+{
+#ifdef WITH_PARTIO
+ m_attr_queries.push_back(AttrQuery());
+ AttrQuery &query = m_attr_queries.back();
+
+ /* make space for what we need. the only reason to use
+ std::vector is to skip the delete */
+ query.attr_names.resize(nattrs);
+ query.attr_partio_types.resize(nattrs);
+ /* capacity will keep the length of the smallest array passed
+ to the query. Just to prevent buffer overruns */
+ query.capacity = -1;
+
+ for(int i = 0; i < nattrs; ++i)
+ {
+ query.attr_names[i] = attr_names[i];
+
+ TypeDesc element_type = attr_types[i].elementtype ();
+
+ if(query.capacity < 0)
+ query.capacity = attr_types[i].numelements();
+ else
+ query.capacity = min(query.capacity, (int)attr_types[i].numelements());
+
+ /* convert the OSL (OIIO) type to the equivalent Partio type so
+ we can do a fast check at query time. */
+ if(element_type == TypeDesc::TypeFloat)
+ query.attr_partio_types[i] = Partio::FLOAT;
+ else if(element_type == TypeDesc::TypeInt)
+ query.attr_partio_types[i] = Partio::INT;
+ else if(element_type == TypeDesc::TypeColor || element_type == TypeDesc::TypePoint ||
+ element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal)
+ query.attr_partio_types[i] = Partio::VECTOR;
+ else
+ return NULL; /* report some error of unknown type */
+ }
+
+ /* this is valid until the end of RenderServices */
+ return &query;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef WITH_PARTIO
+Partio::ParticlesData *OSLRenderServices::get_pointcloud(ustring filename)
+{
+ return Partio::readCached(filename.c_str(), true);
+}
+
+#endif
+
+int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, float radius,
+ int max_points, void *_attr_query, void **attr_outdata)
+{
+ /* todo: this code has never been tested, and most likely does not
+ work. it's based on the example code in OSL */
+
+#ifdef WITH_PARTIO
+ /* query Partio for this pointcloud lookup using cached attr_query */
+ if(!_attr_query)
+ return 0;
+
+ AttrQuery *attr_query = (AttrQuery *)_attr_query;
+ if(attr_query->capacity < max_points)
+ return 0;
+
+ /* get the pointcloud entry for the given filename */
+ Partio::ParticlesData *cloud = get_pointcloud(filename);
+
+ /* now we have to look up all the attributes in the file. we can't do this
+ before hand cause we never know what we are going to load. */
+ int nattrs = attr_query->attr_names.size();
+ Partio::ParticleAttribute *attr = (Partio::ParticleAttribute *)alloca(sizeof(Partio::ParticleAttribute) * nattrs);
+
+ for(int i = 0; i < nattrs; ++i) {
+ /* special case attributes */
+ if(attr_query->attr_names[i] == u_distance || attr_query->attr_names[i] == u_index)
+ continue;
+
+ /* lookup the attribute by name*/
+ if(!cloud->attributeInfo(attr_query->attr_names[i].c_str(), attr[i])) {
+ /* issue an error here and return, types don't match */
+ Partio::endCachedAccess(cloud);
+ cloud->release();
+ return 0;
+ }
+ }
+
+ std::vector<Partio::ParticleIndex> indices;
+ std::vector<float> dist2;
+
+ Partio::beginCachedAccess(cloud);
+
+ /* finally, do the lookup */
+ cloud->findNPoints((const float *)&center, max_points, radius, indices, dist2);
+ int count = indices.size();
+
+ /* retrieve the attributes directly to user space */
+ for(int j = 0; j < nattrs; ++j) {
+ /* special cases */
+ if(attr_query->attr_names[j] == u_distance) {
+ for(int i = 0; i < count; ++i)
+ ((float *)attr_outdata[j])[i] = sqrtf(dist2[i]);
+ }
+ else if(attr_query->attr_names[j] == u_index) {
+ for(int i = 0; i < count; ++i)
+ ((int *)attr_outdata[j])[i] = indices[i];
+ }
+ else {
+ /* note we make a single call per attribute, we don't loop over the
+ points. Partio does it, so it is there that we have to care about
+ performance */
+ cloud->data(attr[j], count, &indices[0], true, attr_outdata[j]);
+ }
+ }
+
+ Partio::endCachedAccess(cloud);
+ cloud->release();
+
+ return count;
+#else
+ return 0;
+#endif
+}
+
+CCL_NAMESPACE_END
+