Blender V2.61 - r43446
|
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 ¢er, 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 *)¢er, 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