Blender V2.61 - r43446

osl_services.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include <string.h>
00020 
00021 #include "mesh.h"
00022 #include "object.h"
00023 #include "scene.h"
00024 
00025 #include "osl_services.h"
00026 #include "osl_shader.h"
00027 
00028 #include "util_foreach.h"
00029 #include "util_string.h"
00030 
00031 #include "kernel_compat_cpu.h"
00032 #include "kernel_globals.h"
00033 #include "kernel_object.h"
00034 #include "kernel_triangle.h"
00035 
00036 CCL_NAMESPACE_BEGIN
00037 
00038 /* RenderServices implementation */
00039 
00040 #define TO_MATRIX44(m) (*(OSL::Matrix44*)&(m))
00041 
00042 /* static ustrings */
00043 ustring OSLRenderServices::u_distance("distance");
00044 ustring OSLRenderServices::u_index("index");
00045 ustring OSLRenderServices::u_camera("camera");
00046 ustring OSLRenderServices::u_screen("screen");
00047 ustring OSLRenderServices::u_raster("raster");
00048 ustring OSLRenderServices::u_ndc("NDC");
00049 ustring OSLRenderServices::u_empty;
00050 
00051 OSLRenderServices::OSLRenderServices()
00052 {
00053     kernel_globals = NULL;
00054 }
00055 
00056 OSLRenderServices::~OSLRenderServices()
00057 {
00058 }
00059 
00060 void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_)
00061 {
00062     kernel_globals = kernel_globals_;
00063 }
00064 
00065 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
00066 {
00067     /* this is only used for shader and object space, we don't really have
00068        a concept of shader space, so we just use object space for both. */
00069     if(xform) {
00070         KernelGlobals *kg = kernel_globals;
00071         const ShaderData *sd = (const ShaderData*)xform;
00072         int object = sd->object;
00073 
00074         if(object != ~0) {
00075             Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
00076             tfm = transform_transpose(tfm);
00077             result = TO_MATRIX44(tfm);
00078 
00079             return true;
00080         }
00081     }
00082 
00083     return false;
00084 }
00085 
00086 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
00087 {
00088     /* this is only used for shader and object space, we don't really have
00089        a concept of shader space, so we just use object space for both. */
00090     if(xform) {
00091         KernelGlobals *kg = kernel_globals;
00092         const ShaderData *sd = (const ShaderData*)xform;
00093         int object = sd->object;
00094 
00095         if(object != ~0) {
00096             Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
00097             tfm = transform_transpose(tfm);
00098             result = TO_MATRIX44(tfm);
00099 
00100             return true;
00101         }
00102     }
00103 
00104     return false;
00105 }
00106 
00107 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time)
00108 {
00109     KernelGlobals *kg = kernel_globals;
00110 
00111     if(from == u_ndc) {
00112         Transform tfm = transform_transpose(kernel_data.cam.ndctoworld);
00113         result = TO_MATRIX44(tfm);
00114         return true;
00115     }
00116     else if(from == u_raster) {
00117         Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
00118         result = TO_MATRIX44(tfm);
00119         return true;
00120     }
00121     else if(from == u_screen) {
00122         Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
00123         result = TO_MATRIX44(tfm);
00124         return true;
00125     }
00126     else if(from == u_camera) {
00127         Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
00128         result = TO_MATRIX44(tfm);
00129         return true;
00130     }
00131 
00132     return false;
00133 }
00134 
00135 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time)
00136 {
00137     KernelGlobals *kg = kernel_globals;
00138 
00139     if(to == u_ndc) {
00140         Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
00141         result = TO_MATRIX44(tfm);
00142         return true;
00143     }
00144     else if(to == u_raster) {
00145         Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
00146         result = TO_MATRIX44(tfm);
00147         return true;
00148     }
00149     else if(to == u_screen) {
00150         Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
00151         result = TO_MATRIX44(tfm);
00152         return true;
00153     }
00154     else if(to == u_camera) {
00155         Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
00156         result = TO_MATRIX44(tfm);
00157         return true;
00158     }
00159 
00160     return false;
00161 }
00162 
00163 bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives, 
00164     ustring object, TypeDesc type, ustring name,
00165     int index, void *val)
00166 {
00167     return false;
00168 }
00169 
00170 static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd,
00171     const OSLGlobals::Attribute& attr, bool derivatives, void *val)
00172 {
00173     if(attr.type == TypeDesc::TypeFloat) {
00174         float *fval = (float*)val;
00175         fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
00176             (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL);
00177     }
00178     else {
00179         /* todo: this won't work when float3 has w component */
00180         float3 *fval = (float3*)val;
00181         fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
00182             (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL);
00183     }
00184 
00185     return true;
00186 }
00187 
00188 static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd,
00189     const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val)
00190 {
00191     if(attr.type == TypeDesc::TypeFloat) {
00192         float tmp[3];
00193         float3 *fval = (float3*)val;
00194 
00195         get_mesh_attribute(kg, sd, attr, derivatives, tmp);
00196 
00197         fval[0] = make_float3(tmp[0], tmp[0], tmp[0]);
00198         if(derivatives) {
00199             fval[1] = make_float3(tmp[1], tmp[1], tmp[1]);
00200             fval[2] = make_float3(tmp[2], tmp[2], tmp[2]);
00201         }
00202 
00203         return true;
00204     }
00205     else if(attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
00206         attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
00207         float3 tmp[3];
00208         float *fval = (float*)val;
00209 
00210         get_mesh_attribute(kg, sd, attr, derivatives, tmp);
00211 
00212         fval[0] = average(tmp[0]);
00213         if(derivatives) {
00214             fval[1] = average(tmp[1]);
00215             fval[2] = average(tmp[2]);
00216         }
00217 
00218         return true;
00219     }
00220     else
00221         return false;
00222 }
00223 
00224 static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
00225 {
00226     size_t datasize = attr.value.datasize();
00227 
00228     memcpy(val, attr.value.data(), datasize);
00229     if(derivatives)
00230         memset((char*)val + datasize, 0, datasize*2);
00231 }
00232 
00233 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
00234     TypeDesc type, ustring name, void *val)
00235 {
00236     KernelGlobals *kg = kernel_globals;
00237     const ShaderData *sd = (const ShaderData*)renderstate;
00238     int object = sd->object;
00239     int tri = sd->prim;
00240 
00241     /* lookup of attribute on another object */
00242     if(object_name != u_empty) {
00243         OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
00244 
00245         if(it == kg->osl.object_name_map.end())
00246             return false;
00247 
00248         object = it->second;
00249         tri = ~0;
00250     }
00251     else if(object == ~0) {
00252         /* no background attributes supported */
00253         return false;
00254     }
00255 
00256     /* find attribute on object */
00257     OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
00258     OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
00259 
00260     if(it == attribute_map.end())
00261         return false;
00262 
00263     /* type mistmatch? */
00264     const OSLGlobals::Attribute& attr = it->second;
00265 
00266     if(attr.elem != ATTR_ELEMENT_VALUE) {
00267         /* triangle and vertex attributes */
00268         if(tri != ~0) {
00269             if(attr.type == type || (attr.type == TypeDesc::TypeColor &&
00270                 (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal)))
00271                 return get_mesh_attribute(kg, sd, attr, derivatives, val);
00272             else
00273                 return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val);
00274         }
00275     }
00276     else {
00277         /* object attribute */
00278         get_object_attribute(attr, derivatives, val);
00279         return true;
00280     }
00281 
00282     return false;
00283 }
00284 
00285 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
00286     void *renderstate, void *val)
00287 {
00288     return false; /* disabled by lockgeom */
00289 }
00290 
00291 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
00292 {
00293     return false; /* never called by OSL */
00294 }
00295 
00296 void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names,
00297     TypeDesc *attr_types, int nattrs)
00298 {
00299 #ifdef WITH_PARTIO
00300     m_attr_queries.push_back(AttrQuery());
00301     AttrQuery &query = m_attr_queries.back();
00302 
00303     /* make space for what we need. the only reason to use
00304        std::vector is to skip the delete */
00305     query.attr_names.resize(nattrs);
00306     query.attr_partio_types.resize(nattrs);
00307     /* capacity will keep the length of the smallest array passed
00308        to the query. Just to prevent buffer overruns */
00309     query.capacity = -1;
00310 
00311     for(int i = 0; i < nattrs; ++i)
00312     {
00313         query.attr_names[i] = attr_names[i];
00314 
00315         TypeDesc element_type = attr_types[i].elementtype ();
00316 
00317         if(query.capacity < 0)
00318            query.capacity = attr_types[i].numelements();
00319         else
00320            query.capacity = min(query.capacity, (int)attr_types[i].numelements());
00321 
00322         /* convert the OSL (OIIO) type to the equivalent Partio type so
00323            we can do a fast check at query time. */
00324         if(element_type == TypeDesc::TypeFloat)
00325            query.attr_partio_types[i] = Partio::FLOAT;
00326         else if(element_type == TypeDesc::TypeInt)
00327            query.attr_partio_types[i] = Partio::INT;
00328         else if(element_type == TypeDesc::TypeColor  || element_type == TypeDesc::TypePoint ||
00329                  element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal)
00330            query.attr_partio_types[i] = Partio::VECTOR;
00331         else
00332             return NULL; /* report some error of unknown type */
00333     }
00334 
00335     /* this is valid until the end of RenderServices */
00336     return &query;
00337 #else
00338     return NULL;
00339 #endif
00340 }
00341 
00342 #ifdef WITH_PARTIO
00343 Partio::ParticlesData *OSLRenderServices::get_pointcloud(ustring filename)
00344 {
00345     return Partio::readCached(filename.c_str(), true);
00346 }
00347 
00348 #endif
00349 
00350 int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, float radius,
00351     int max_points, void *_attr_query, void **attr_outdata)
00352 {
00353     /* todo: this code has never been tested, and most likely does not
00354        work. it's based on the example code in OSL */
00355 
00356 #ifdef WITH_PARTIO
00357     /* query Partio for this pointcloud lookup using cached attr_query */
00358     if(!_attr_query)
00359         return 0;
00360 
00361     AttrQuery *attr_query = (AttrQuery *)_attr_query;
00362     if(attr_query->capacity < max_points)
00363         return 0;
00364 
00365     /* get the pointcloud entry for the given filename */
00366     Partio::ParticlesData *cloud = get_pointcloud(filename);
00367 
00368     /* now we have to look up all the attributes in the file. we can't do this
00369        before hand cause we never know what we are going to load. */
00370     int nattrs = attr_query->attr_names.size();
00371     Partio::ParticleAttribute *attr = (Partio::ParticleAttribute *)alloca(sizeof(Partio::ParticleAttribute) * nattrs);
00372 
00373     for(int i = 0; i < nattrs; ++i) {
00374         /* special case attributes */
00375         if(attr_query->attr_names[i] == u_distance || attr_query->attr_names[i] == u_index)
00376             continue;
00377 
00378         /* lookup the attribute by name*/
00379         if(!cloud->attributeInfo(attr_query->attr_names[i].c_str(), attr[i])) {
00380             /* issue an error here and return, types don't match */
00381             Partio::endCachedAccess(cloud);
00382             cloud->release();
00383             return 0;
00384         }
00385     }
00386 
00387     std::vector<Partio::ParticleIndex> indices;
00388     std::vector<float> dist2;
00389 
00390     Partio::beginCachedAccess(cloud);
00391 
00392     /* finally, do the lookup */
00393     cloud->findNPoints((const float *)&center, max_points, radius, indices, dist2);
00394     int count = indices.size();
00395 
00396     /* retrieve the attributes directly to user space */
00397     for(int j = 0; j < nattrs; ++j) {
00398         /* special cases */
00399         if(attr_query->attr_names[j] == u_distance) {
00400             for(int i = 0; i < count; ++i)
00401                 ((float *)attr_outdata[j])[i] = sqrtf(dist2[i]);
00402         }
00403         else if(attr_query->attr_names[j] == u_index) {
00404             for(int i = 0; i < count; ++i)
00405                 ((int *)attr_outdata[j])[i] = indices[i];
00406         }
00407         else {
00408             /* note we make a single call per attribute, we don't loop over the
00409                points. Partio does it, so it is there that we have to care about
00410                performance */
00411             cloud->data(attr[j], count, &indices[0], true, attr_outdata[j]);
00412         }
00413     }
00414 
00415     Partio::endCachedAccess(cloud);
00416     cloud->release();
00417 
00418     return count;
00419 #else
00420     return 0;
00421 #endif
00422 }
00423 
00424 CCL_NAMESPACE_END
00425