// The --expr ARG command line option will take ARG that is a snipped of // OSL source code, embed it in some boilerplate shader wrapper, compile // it from memory, and run that in the same way that would have been done // if it were a compiled shader on disk. The boilerplate assumes that there // are two output parameters for the shader: color result, and float alpha. // // Example use: // testshade -v -g 64 64 -o result out.exr -expr 'result=color(u,v,0);' // static void specify_expr (int argc, const char *argv[]) { ASSERT (argc == 2); std::string shadername = OIIO::Strutil::format("expr_%d", exprcount++); std::string sourcecode = "shader " + shadername + " (\n" " float s = u [[ int lockgeom=0 ]],\n" " float t = v [[ int lockgeom=0 ]],\n" " output color result = 0,\n" " output float alpha = 1,\n" " )\n" "{\n" " " + std::string(argv[1]) + "\n" " ;\n" "}\n"; if (verbose) std::cout << "Expression-based shader text is:\n---\n" << sourcecode << "---\n"; set_shadingsys_options (); compile_buffer (sourcecode, shadername); inject_params (); shadernames.push_back (shadername); shadingsys->Shader ("surface", shadername, layername); layername.clear (); params.clear (); }
static int add_shader (int argc, const char *argv[]) { shadingsys->attribute ("debug", debug2 ? 2 : (debug ? 1 : 0)); const char *opt_env = getenv ("TESTSHADE_OPT"); // overrides opt if (opt_env) shadingsys->attribute ("optimize", atoi(opt_env)); else if (O0 || O1 || O2) shadingsys->attribute ("optimize", O2 ? 2 : (O1 ? 1 : 0)); shadingsys->attribute ("lockgeom", 1); shadingsys->attribute ("debug_nan", debugnan); shadingsys->attribute ("debug_uninit", debug_uninit); for (int i = 0; i < argc; i++) { inject_params (); shadernames.push_back (argv[i]); shadingsys->Shader ("surface", argv[i], layername.length() ? layername.c_str() : NULL); layername.clear (); params.clear (); } return 0; }
static void inject_params () { for (size_t p = 0; p < params.size(); ++p) { const ParamValue &pv (params[p]); shadingsys->Parameter (pv.name().c_str(), pv.type(), pv.data(), pv.interp() == ParamValue::INTERP_CONSTANT); } }
static int add_shader (int argc, const char *argv[]) { ASSERT (argc == 1); string_view shadername (argv[0]); set_shadingsys_options (); if (inbuffer) // Request to exercise the buffer-based API calls shader_from_buffers (shadername); for (int i = 0; i < argc; i++) { inject_params (); shadernames.push_back (shadername); shadingsys->Shader ("surface", shadername, layername); layername.clear (); params.clear (); } return 0; }
extern "C" int test_shade (int argc, const char *argv[]) { OIIO::Timer timer; // Create a new shading system. We pass it the RendererServices // object that services callbacks from the shading system, NULL for // the TextureSystem (that just makes 'create' make its own TS), and // an error handler. shadingsys = ShadingSystem::create (&rend, NULL, &errhandler); register_closures(shadingsys); // Remember that each shader parameter may optionally have a // metadata hint [[int lockgeom=...]], where 0 indicates that the // parameter may be overridden by the geometry itself, for example // with data interpolated from the mesh vertices, and a value of 1 // means that it is "locked" with respect to the geometry (i.e. it // will not be overridden with interpolated or // per-geometric-primitive data). // // In order to most fully optimize shader, we typically want any // shader parameter not explicitly specified to default to being // locked (i.e. no per-geometry override): shadingsys->attribute("lockgeom", 1); // Now we declare our shader. // // Each material in the scene is comprised of a "shader group." // Each group is comprised of one or more "layers" (a.k.a. shader // instances) with possible connections from outputs of // upstream/early layers into the inputs of downstream/later layers. // A shader instance is the combination of a reference to a shader // master and its parameter values that may override the defaults in // the shader source and may be particular to this instance (versus // all the other instances of the same shader). // // A shader group declaration typically looks like this: // // ShaderGroupRef shadergroup = ss->ShaderGroupBegin (); // ss->Parameter ("paramname", TypeDesc paramtype, void *value); // ... and so on for all the other parameters of... // ss->Shader ("shadertype", "shadername", "layername"); // The Shader() call creates a new instance, which gets // all the pending Parameter() values made right before it. // ... and other shader instances in this group, interspersed with... // ss->ConnectShaders ("layer1", "param1", "layer2", "param2"); // ... and other connections ... // ss->ShaderGroupEnd (); // // It looks so simple, and it really is, except that the way this // testshade program works is that all the Parameter() and Shader() // calls are done inside getargs(), as it walks through the command // line arguments, whereas the connections accumulate and have // to be processed at the end. Bear with us. // Start the shader group and grab a reference to it. ShaderGroupRef shadergroup = shadingsys->ShaderGroupBegin (); // Get the command line arguments. That will set up all the shader // instances and their parameters for the group. getargs (argc, argv); // Now set up the connections for (size_t i = 0; i < connections.size(); i += 4) { if (i+3 < connections.size()) { std::cout << "Connect " << connections[i] << "." << connections[i+1] << " to " << connections[i+2] << "." << connections[i+3] << "\n"; shadingsys->ConnectShaders (connections[i].c_str(), connections[i+1].c_str(), connections[i+2].c_str(), connections[i+3].c_str()); } } // End the group shadingsys->ShaderGroupEnd (); if (outputfiles.size() != 0) std::cout << "\n"; // Set up the named transformations, including shader and object. // For this test application, we just do this statically; in a real // renderer, the global named space (like "myspace") would probably // be static, but shader and object spaces may be different for each // object. setup_transformations (rend, Mshad, Mobj); // Set up the image outputs requested on the command line setup_output_images (shadingsys, shadergroup); // Set up shader globals and a little test grid of points to shade. ShaderGlobals shaderglobals; double setuptime = timer.lap (); // Optional: high-performance apps may request this thread-specific // pointer in order to save a bit of time on each shade. Just like // the name implies, a multithreaded renderer would need to do this // separately for each thread, and be careful to always use the same // thread_info each time for that thread. // // There's nothing wrong with a simpler app just passing NULL for // the thread_info; in such a case, the ShadingSystem will do the // necessary calls to find the thread-specific pointer itself, but // this will degrade performance just a bit. OSL::PerThreadInfo *thread_info = shadingsys->create_thread_info(); // Request a shading context so that we can execute the shader. // We could get_context/release_constext for each shading point, // but to save overhead, it's more efficient to reuse a context // within a thread. ShadingContext *ctx = shadingsys->get_context (thread_info); // Allow a settable number of iterations to "render" the whole image, // which is useful for time trials of things that would be too quick // to accurately time for a single iteration for (int iter = 0; iter < iters; ++iter) { // Loop over all pixels in the image (in x and y)... for (int y = 0, n = 0; y < yres; ++y) { for (int x = 0; x < xres; ++x, ++n) { // In a real renderer, this is where you would figure // out what object point is visible in this pixel (or // this sample, for antialiasing). Once determined, // you'd set up a ShaderGlobals that contained the vital // information about that point, such as its location, // the normal there, the u and v coordinates on the // surface, the transformation of that object, and so // on. // // This test app is not a real renderer, so we just // set it up rigged to look like we're rendering a single // quadrilateral that exactly fills the viewport, and that // setup is done in the following function call: setup_shaderglobals (shaderglobals, shadingsys, x, y); // Actually run the shader for this point shadingsys->execute (*ctx, *shadergroup, shaderglobals); // Save all the designated outputs. But only do so if we // are on the last iteration requested, so that if we are // doing a bunch of iterations for time trials, we only // including the output pixel copying once in the timing. if (iter == (iters - 1)) { save_outputs (shadingsys, ctx, x, y); } } } // If any reparam was requested, do it now if (reparams.size() && reparam_layer.size()) { for (size_t p = 0; p < reparams.size(); ++p) { const ParamValue &pv (reparams[p]); shadingsys->ReParameter (*shadergroup, reparam_layer.c_str(), pv.name().c_str(), pv.type(), pv.data()); } } } // We're done shading with this context. shadingsys->release_context (ctx); // Now that we're done rendering, release the thread=specific // pointer we saved. A simple app could skip this; but if the app // asks for it (as we have in this example), then it should also // destroy it when done with it. shadingsys->destroy_thread_info(thread_info); if (outputfiles.size() == 0) std::cout << "\n"; // Write the output images to disk for (size_t i = 0; i < outputimgs.size(); ++i) { if (outputimgs[i]) { outputimgs[i]->save(); delete outputimgs[i]; outputimgs[i] = NULL; } } // Print some debugging info if (debug || stats) { double runtime = timer.lap(); std::cout << "\n"; std::cout << "Setup: " << OIIO::Strutil::timeintervalformat (setuptime,2) << "\n"; std::cout << "Run : " << OIIO::Strutil::timeintervalformat (runtime,2) << "\n"; std::cout << "\n"; std::cout << shadingsys->getstats (5) << "\n"; } // We're done with the shading system now, destroy it shadergroup.reset (); // Must release this before destroying shadingsys ShadingSystem::destroy (shadingsys); return EXIT_SUCCESS; }
static void action_param (int argc, const char *argv[]) { std::string command = argv[0]; bool use_reparam = false; if (OIIO::Strutil::istarts_with(command, "--reparam") || OIIO::Strutil::istarts_with(command, "-reparam")) use_reparam = true; ParamValueList ¶ms (use_reparam ? reparams : (::params)); std::string paramname = argv[1]; std::string stringval = argv[2]; TypeDesc type = TypeDesc::UNKNOWN; bool unlockgeom = false; float f[16]; size_t pos; while ((pos = command.find_first_of(":")) != std::string::npos) { command = command.substr (pos+1, std::string::npos); std::vector<std::string> splits; OIIO::Strutil::split (command, splits, ":", 1); if (splits.size() < 1) {} else if (OIIO::Strutil::istarts_with(splits[0],"type=")) type.fromstring (splits[0].c_str()+5); else if (OIIO::Strutil::istarts_with(splits[0],"lockgeom=")) unlockgeom = (strtol (splits[0].c_str()+9, NULL, 10) == 0); } // If it is or might be a matrix, look for 16 comma-separated floats if ((type == TypeDesc::UNKNOWN || type == TypeDesc::TypeMatrix) && sscanf (stringval.c_str(), "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9], &f[10], &f[11], &f[12], &f[13], &f[14], &f[15]) == 16) { params.push_back (ParamValue()); params.back().init (paramname, TypeDesc::TypeMatrix, 1, f); if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // If it is or might be a vector type, look for 3 comma-separated floats if ((type == TypeDesc::UNKNOWN || equivalent(type,TypeDesc::TypeVector)) && sscanf (stringval.c_str(), "%g, %g, %g", &f[0], &f[1], &f[2]) == 3) { if (type == TypeDesc::UNKNOWN) type = TypeDesc::TypeVector; params.push_back (ParamValue()); params.back().init (paramname, type, 1, f); if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // If it is or might be an int, look for an int that takes up the whole // string. if ((type == TypeDesc::UNKNOWN || type == TypeDesc::TypeInt)) { char *endptr = NULL; int ival = strtol(stringval.c_str(),&endptr,10); if (endptr && *endptr == 0) { params.push_back (ParamValue()); params.back().init (paramname, TypeDesc::TypeInt, 1, &ival); if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } } // If it is or might be an float, look for a float that takes up the // whole string. if ((type == TypeDesc::UNKNOWN || type == TypeDesc::TypeFloat)) { char *endptr = NULL; float fval = (float) strtod(stringval.c_str(),&endptr); if (endptr && *endptr == 0) { params.push_back (ParamValue()); params.back().init (paramname, TypeDesc::TypeFloat, 1, &fval); if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } } // All remaining cases -- it's a string const char *s = stringval.c_str(); params.push_back (ParamValue()); params.back().init (paramname, TypeDesc::TypeString, 1, &s); if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); }
extern "C" OSL_DLL_EXPORT int test_shade (int argc, const char *argv[]) { OIIO::Timer timer; // Create a new shading system. We pass it the RendererServices // object that services callbacks from the shading system, NULL for // the TextureSystem (that just makes 'create' make its own TS), and // an error handler. shadingsys = new ShadingSystem (&rend, NULL, &errhandler); // Register the layout of all closures known to this renderer // Any closure used by the shader which is not registered, or // registered with a different number of arguments will lead // to a runtime error. register_closures(shadingsys); // Remember that each shader parameter may optionally have a // metadata hint [[int lockgeom=...]], where 0 indicates that the // parameter may be overridden by the geometry itself, for example // with data interpolated from the mesh vertices, and a value of 1 // means that it is "locked" with respect to the geometry (i.e. it // will not be overridden with interpolated or // per-geometric-primitive data). // // In order to most fully optimize shader, we typically want any // shader parameter not explicitly specified to default to being // locked (i.e. no per-geometry override): shadingsys->attribute("lockgeom", 1); // Now we declare our shader. // // Each material in the scene is comprised of a "shader group." // Each group is comprised of one or more "layers" (a.k.a. shader // instances) with possible connections from outputs of // upstream/early layers into the inputs of downstream/later layers. // A shader instance is the combination of a reference to a shader // master and its parameter values that may override the defaults in // the shader source and may be particular to this instance (versus // all the other instances of the same shader). // // A shader group declaration typically looks like this: // // ShaderGroupRef shadergroup = ss->ShaderGroupBegin (); // ss->Parameter ("paramname", TypeDesc paramtype, void *value); // ... and so on for all the other parameters of... // ss->Shader ("shadertype", "shadername", "layername"); // The Shader() call creates a new instance, which gets // all the pending Parameter() values made right before it. // ... and other shader instances in this group, interspersed with... // ss->ConnectShaders ("layer1", "param1", "layer2", "param2"); // ... and other connections ... // ss->ShaderGroupEnd (); // // It looks so simple, and it really is, except that the way this // testshade program works is that all the Parameter() and Shader() // calls are done inside getargs(), as it walks through the command // line arguments, whereas the connections accumulate and have // to be processed at the end. Bear with us. // Start the shader group and grab a reference to it. shadergroup = shadingsys->ShaderGroupBegin (groupname); // Get the command line arguments. That will set up all the shader // instances and their parameters for the group. getargs (argc, argv); if (! shadergroup) { std::cerr << "ERROR: Invalid shader group. Exiting testshade.\n"; return EXIT_FAILURE; } shadingsys->attribute (shadergroup.get(), "groupname", groupname); // Now set up the connections for (size_t i = 0; i < connections.size(); i += 4) { if (i+3 < connections.size()) { std::cout << "Connect " << connections[i] << "." << connections[i+1] << " to " << connections[i+2] << "." << connections[i+3] << "\n"; shadingsys->ConnectShaders (connections[i].c_str(), connections[i+1].c_str(), connections[i+2].c_str(), connections[i+3].c_str()); } } // End the group shadingsys->ShaderGroupEnd (); if (verbose || do_oslquery) { std::string pickle; shadingsys->getattribute (shadergroup.get(), "pickle", pickle); std::cout << "Shader group:\n---\n" << pickle << "\n---\n"; std::cout << "\n"; ustring groupname; shadingsys->getattribute (shadergroup.get(), "groupname", groupname); std::cout << "Shader group \"" << groupname << "\" layers are:\n"; int num_layers = 0; shadingsys->getattribute (shadergroup.get(), "num_layers", num_layers); if (num_layers > 0) { std::vector<const char *> layers (size_t(num_layers), NULL); shadingsys->getattribute (shadergroup.get(), "layer_names", TypeDesc(TypeDesc::STRING, num_layers), &layers[0]); for (int i = 0; i < num_layers; ++i) { std::cout << " " << (layers[i] ? layers[i] : "<unnamed>") << "\n"; if (do_oslquery) { OSLQuery q; q.init (shadergroup.get(), i); for (size_t p = 0; p < q.nparams(); ++p) { const OSLQuery::Parameter *param = q.getparam(p); std::cout << "\t" << (param->isoutput ? "output " : "") << param->type << ' ' << param->name << "\n"; } } } } std::cout << "\n"; } if (archivegroup.size()) shadingsys->archive_shadergroup (shadergroup.get(), archivegroup); if (outputfiles.size() != 0) std::cout << "\n"; // Set up the named transformations, including shader and object. // For this test application, we just do this statically; in a real // renderer, the global named space (like "myspace") would probably // be static, but shader and object spaces may be different for each // object. setup_transformations (rend, Mshad, Mobj); // Set up the image outputs requested on the command line setup_output_images (shadingsys, shadergroup); if (debug) test_group_attributes (shadergroup.get()); if (num_threads < 1) num_threads = boost::thread::hardware_concurrency(); double setuptime = timer.lap (); // Allow a settable number of iterations to "render" the whole image, // which is useful for time trials of things that would be too quick // to accurately time for a single iteration for (int iter = 0; iter < iters; ++iter) { OIIO::ROI roi (0, xres, 0, yres); if (use_shade_image) OSL::shade_image (*shadingsys, *shadergroup, NULL, *outputimgs[0], outputvarnames, pixelcenters ? ShadePixelCenters : ShadePixelGrid, roi, num_threads); else { bool save = (iter == (iters-1)); // save on last iteration #if 0 shade_region (shadergroup.get(), roi, save); #else OIIO::ImageBufAlgo::parallel_image ( boost::bind (shade_region, shadergroup.get(), _1, save), roi, num_threads); #endif } // If any reparam was requested, do it now if (reparams.size() && reparam_layer.size()) { for (size_t p = 0; p < reparams.size(); ++p) { const ParamValue &pv (reparams[p]); shadingsys->ReParameter (*shadergroup, reparam_layer.c_str(), pv.name().c_str(), pv.type(), pv.data()); } } } double runtime = timer.lap(); if (outputfiles.size() == 0) std::cout << "\n"; // Write the output images to disk for (size_t i = 0; i < outputimgs.size(); ++i) { if (outputimgs[i]) { if (! print_outputs) { std::string filename = outputimgs[i]->name(); // JPEG, GIF, and PNG images should be automatically saved // as sRGB because they are almost certainly supposed to // be displayed on web pages. using namespace OIIO; if (Strutil::iends_with (filename, ".jpg") || Strutil::iends_with (filename, ".jpeg") || Strutil::iends_with (filename, ".gif") || Strutil::iends_with (filename, ".png")) { ImageBuf ccbuf; ImageBufAlgo::colorconvert (ccbuf, *outputimgs[i], "linear", "sRGB", false, "", ""); ccbuf.set_write_format (outputimgs[i]->spec().format); ccbuf.write (filename); } else { outputimgs[i]->write (filename); } } delete outputimgs[i]; outputimgs[i] = NULL; } } // Print some debugging info if (debug || runstats || profile) { double writetime = timer.lap(); std::cout << "\n"; std::cout << "Setup: " << OIIO::Strutil::timeintervalformat (setuptime,2) << "\n"; std::cout << "Run : " << OIIO::Strutil::timeintervalformat (runtime,2) << "\n"; std::cout << "Write: " << OIIO::Strutil::timeintervalformat (writetime,2) << "\n"; std::cout << "\n"; std::cout << shadingsys->getstats (5) << "\n"; OIIO::TextureSystem *texturesys = shadingsys->texturesys(); if (texturesys) std::cout << texturesys->getstats (5) << "\n"; std::cout << ustring::getstats() << "\n"; } // We're done with the shading system now, destroy it shadergroup.reset (); // Must release this before destroying shadingsys delete shadingsys; return EXIT_SUCCESS; }
extern "C" int test_shade (int argc, const char *argv[]) { OIIO::Timer timer; // Create a new shading system. We pass it the RendererServices // object that services callbacks from the shading system, NULL for // the TextureSystem (that just makes 'create' make its own TS), and // an error handler. shadingsys = new ShadingSystem (&rend, NULL, &errhandler); register_closures(shadingsys); // Remember that each shader parameter may optionally have a // metadata hint [[int lockgeom=...]], where 0 indicates that the // parameter may be overridden by the geometry itself, for example // with data interpolated from the mesh vertices, and a value of 1 // means that it is "locked" with respect to the geometry (i.e. it // will not be overridden with interpolated or // per-geometric-primitive data). // // In order to most fully optimize shader, we typically want any // shader parameter not explicitly specified to default to being // locked (i.e. no per-geometry override): shadingsys->attribute("lockgeom", 1); // Now we declare our shader. // // Each material in the scene is comprised of a "shader group." // Each group is comprised of one or more "layers" (a.k.a. shader // instances) with possible connections from outputs of // upstream/early layers into the inputs of downstream/later layers. // A shader instance is the combination of a reference to a shader // master and its parameter values that may override the defaults in // the shader source and may be particular to this instance (versus // all the other instances of the same shader). // // A shader group declaration typically looks like this: // // ShaderGroupRef shadergroup = ss->ShaderGroupBegin (); // ss->Parameter ("paramname", TypeDesc paramtype, void *value); // ... and so on for all the other parameters of... // ss->Shader ("shadertype", "shadername", "layername"); // The Shader() call creates a new instance, which gets // all the pending Parameter() values made right before it. // ... and other shader instances in this group, interspersed with... // ss->ConnectShaders ("layer1", "param1", "layer2", "param2"); // ... and other connections ... // ss->ShaderGroupEnd (); // // It looks so simple, and it really is, except that the way this // testshade program works is that all the Parameter() and Shader() // calls are done inside getargs(), as it walks through the command // line arguments, whereas the connections accumulate and have // to be processed at the end. Bear with us. // Start the shader group and grab a reference to it. ShaderGroupRef shadergroup = shadingsys->ShaderGroupBegin (); // Get the command line arguments. That will set up all the shader // instances and their parameters for the group. getargs (argc, argv); // Now set up the connections for (size_t i = 0; i < connections.size(); i += 4) { if (i+3 < connections.size()) { std::cout << "Connect " << connections[i] << "." << connections[i+1] << " to " << connections[i+2] << "." << connections[i+3] << "\n"; shadingsys->ConnectShaders (connections[i].c_str(), connections[i+1].c_str(), connections[i+2].c_str(), connections[i+3].c_str()); } } // End the group shadingsys->ShaderGroupEnd (); if (outputfiles.size() != 0) std::cout << "\n"; // Set up the named transformations, including shader and object. // For this test application, we just do this statically; in a real // renderer, the global named space (like "myspace") would probably // be static, but shader and object spaces may be different for each // object. setup_transformations (rend, Mshad, Mobj); // Set up the image outputs requested on the command line setup_output_images (shadingsys, shadergroup); if (debug) test_group_attributes (shadergroup.get()); if (num_threads < 1) num_threads = boost::thread::hardware_concurrency(); double setuptime = timer.lap (); // Allow a settable number of iterations to "render" the whole image, // which is useful for time trials of things that would be too quick // to accurately time for a single iteration for (int iter = 0; iter < iters; ++iter) { OIIO::ROI roi (0, xres, 0, yres); bool save = (iter == (iters-1)); // save on last iteration #if 0 shade_region (shadergroup.get(), roi, save); #else OIIO::ImageBufAlgo::parallel_image ( boost::bind (shade_region, shadergroup.get(), _1, save), roi, num_threads); #endif // If any reparam was requested, do it now if (reparams.size() && reparam_layer.size()) { for (size_t p = 0; p < reparams.size(); ++p) { const ParamValue &pv (reparams[p]); shadingsys->ReParameter (*shadergroup, reparam_layer.c_str(), pv.name().c_str(), pv.type(), pv.data()); } } } if (outputfiles.size() == 0) std::cout << "\n"; // Write the output images to disk for (size_t i = 0; i < outputimgs.size(); ++i) { if (outputimgs[i]) { outputimgs[i]->save(); delete outputimgs[i]; outputimgs[i] = NULL; } } // Print some debugging info if (debug || stats) { double runtime = timer.lap(); std::cout << "\n"; std::cout << "Setup: " << OIIO::Strutil::timeintervalformat (setuptime,2) << "\n"; std::cout << "Run : " << OIIO::Strutil::timeintervalformat (runtime,2) << "\n"; std::cout << "\n"; std::cout << shadingsys->getstats (5) << "\n"; OIIO::TextureSystem *texturesys = shadingsys->texturesys(); if (texturesys) std::cout << texturesys->getstats (5) << "\n"; std::cout << ustring::getstats() << "\n"; } // We're done with the shading system now, destroy it shadergroup.reset (); // Must release this before destroying shadingsys delete shadingsys; return EXIT_SUCCESS; }
static void action_param (int argc, const char *argv[]) { std::string command = argv[0]; bool use_reparam = false; if (OIIO::Strutil::istarts_with(command, "--reparam") || OIIO::Strutil::istarts_with(command, "-reparam")) use_reparam = true; ParamValueList ¶ms (use_reparam ? reparams : (::params)); string_view paramname (argv[1]); string_view stringval (argv[2]); TypeDesc type = TypeDesc::UNKNOWN; bool unlockgeom = false; float f[16]; size_t pos; while ((pos = command.find_first_of(":")) != std::string::npos) { command = command.substr (pos+1, std::string::npos); std::vector<std::string> splits; OIIO::Strutil::split (command, splits, ":", 1); if (splits.size() < 1) {} else if (OIIO::Strutil::istarts_with(splits[0],"type=")) type.fromstring (splits[0].c_str()+5); else if (OIIO::Strutil::istarts_with(splits[0],"lockgeom=")) unlockgeom = (OIIO::Strutil::from_string<int> (splits[0]) == 0); } // If it is or might be a matrix, look for 16 comma-separated floats if ((type == TypeDesc::UNKNOWN || type == TypeDesc::TypeMatrix) && sscanf (stringval.c_str(), "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &f[0], &f[1], &f[2], &f[3], &f[4], &f[5], &f[6], &f[7], &f[8], &f[9], &f[10], &f[11], &f[12], &f[13], &f[14], &f[15]) == 16) { #if OIIO_VERSION >= 10804 params.emplace_back (paramname, TypeDesc::TypeMatrix, 1, f); #else params.push_back (ParamValue()); params.back().init (paramname, TypeDesc::TypeMatrix, 1, f); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // If it is or might be a vector type, look for 3 comma-separated floats if ((type == TypeDesc::UNKNOWN || equivalent(type,TypeDesc::TypeVector)) && sscanf (stringval.c_str(), "%g, %g, %g", &f[0], &f[1], &f[2]) == 3) { if (type == TypeDesc::UNKNOWN) type = TypeDesc::TypeVector; #if OIIO_VERSION >= 10804 params.emplace_back (paramname, type, 1, f); #else params.push_back (ParamValue()); params.back().init (paramname, type, 1, f); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // If it is or might be an int, look for an int that takes up the whole // string. if ((type == TypeDesc::UNKNOWN || type == TypeDesc::TypeInt) && OIIO::Strutil::string_is<int>(stringval)) { #if OIIO_VERSION >= 10804 params.emplace_back (paramname, OIIO::Strutil::from_string<int>(stringval)); #else params.push_back (ParamValue()); int i = OIIO::Strutil::from_string<int>(stringval); params.back().init (paramname, TypeDesc::TypeInt, 1, &i); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // If it is or might be an float, look for a float that takes up the // whole string. if ((type == TypeDesc::UNKNOWN || type == TypeDesc::TypeFloat) && OIIO::Strutil::string_is<float>(stringval)) { #if OIIO_VERSION >= 10804 params.emplace_back (paramname, OIIO::Strutil::from_string<float>(stringval)); #else params.push_back (ParamValue()); float f = OIIO::Strutil::from_string<float>(stringval); params.back().init (paramname, TypeDesc::TypeFloat, 1, &f); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // Catch-all for float types and arrays if (type.basetype == TypeDesc::FLOAT) { int n = type.aggregate * type.numelements(); std::vector<float> vals (n); for (int i = 0; i < n; ++i) { OIIO::Strutil::parse_float (stringval, vals[i]); OIIO::Strutil::parse_char (stringval, ','); } #if OIIO_VERSION >= 10804 params.emplace_back (paramname, type, 1, &vals[0]); #else params.push_back (ParamValue()); params.back().init (paramname, type, 1, &vals[0]); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // Catch-all for int types and arrays if (type.basetype == TypeDesc::INT) { int n = type.aggregate * type.numelements(); std::vector<int> vals (n); for (int i = 0; i < n; ++i) { OIIO::Strutil::parse_int (stringval, vals[i]); OIIO::Strutil::parse_char (stringval, ','); } #if OIIO_VERSION >= 10804 params.emplace_back (paramname, type, 1, &vals[0]); #else params.push_back (ParamValue()); params.back().init (paramname, type, 1, &vals[0]); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // String arrays are slightly tricky if (type.basetype == TypeDesc::STRING && type.is_array()) { std::vector<string_view> splitelements; OIIO::Strutil::split (stringval, splitelements, ",", type.arraylen); splitelements.resize (type.arraylen); std::vector<ustring> strelements; for (auto&& s : splitelements) strelements.push_back (ustring(s)); #if OIIO_VERSION >= 10804 params.emplace_back (paramname, type, 1, &strelements[0]); #else params.push_back (ParamValue()); params.back().init (paramname, type, 1, &strelements[0]); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); return; } // All remaining cases -- it's a string const char *s = stringval.c_str(); #if OIIO_VERSION >= 10804 params.emplace_back (paramname, TypeDesc::TypeString, 1, &s); #else params.push_back (ParamValue()); params.back().init (paramname, TypeDesc::TypeString, 1, &s); #endif if (unlockgeom) params.back().interp (ParamValue::INTERP_VERTEX); }