/* * Copyright (c) 2013 * Side Effects Software Inc. All rights reserved. * * Redistribution and use of Houdini Development Kit samples in source and * binary forms, with or without modification, are permitted provided that the * following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. The name of Side Effects Software may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *---------------------------------------------------------------------------- * Constant SampleGenerator COP */ #include <UT/UT_DSOVersion.h> #include <UT/UT_Math.h> #include <UT/UT_SysClone.h> #include <OP/OP_OperatorTable.h> #include <PRM/PRM_Include.h> #include <PRM/PRM_Parm.h> #include <TIL/TIL_Plane.h> #include <TIL/TIL_Tile.h> #include "COP2_SampleGenerator.h" using namespace HDK_Sample; COP_GENERATOR_SWITCHER(2, "HDK Sample Generator"); static PRM_Name names[] = { PRM_Name("seed", "Seed"), PRM_Name("ampl", "Amplitude"), }; PRM_Template COP2_SampleGenerator::myTemplateList[] = { PRM_Template(PRM_SWITCHER, 3, &PRMswitcherName, switcher), PRM_Template(PRM_INT_J, TOOL_PARM, 1, &names[0], PRMoneDefaults), PRM_Template(PRM_RGB_J, TOOL_PARM, 4, &names[1], PRMoneDefaults), PRM_Template(), }; OP_TemplatePair COP2_SampleGenerator::myTemplatePair( COP2_SampleGenerator::myTemplateList, &COP2_Generator::myTemplatePair ); OP_VariablePair COP2_SampleGenerator::myVariablePair(0, &COP2_Node::myVariablePair ); OP_Node * COP2_SampleGenerator::myConstructor( OP_Network *net, const char *name, OP_Operator *op) { return new COP2_SampleGenerator(net, name, op); } COP2_SampleGenerator::COP2_SampleGenerator(OP_Network *parent, const char *name, OP_Operator *entry) : COP2_Generator(parent, name, entry) { } COP2_SampleGenerator::~COP2_SampleGenerator() { } // ----------------------------------------------------------------------- /// This method computes the resolution, frame range and planes & formats /// used during the cook. All of these parms are non-animatable. It is called /// first during a cook, or when the information is requested from a node. /// Just because cookSequenceInfo is called, it does not mean that a cook is /// about to start. TIL_Sequence * COP2_SampleGenerator::cookSequenceInfo(OP_ERROR & error) { // If you want the controls in the Image/Sequence pages to // affect planes, format, res, range, use this parent class method. // You can always override them after the call. COP2_Generator::cookSequenceInfo(error); //// ***** Other examples *********** //// Manual setup of sequences //// 1. Clear out any previous values. // mySequence.reset(); //// (optional) To copy an input's sequence information: // const TIL_Sequence *seq = inputInfo ( 0 ); // input # // if(seq) // mySequence = *seq; // else // { error = UT_ERROR_ABORT; return &mySequence; } // should pop an err //// 2. Set up frame range **************** //// Do you want a single image only? ie, time invariant. // mySequence.setSingleImage(1); //// otherwise, animations look like (sample values only): // mySequence.setSingleImage(0); // mySequence.setStart(1); // mySequence.setLength(300); // mySequence.setFrameRate(30); //// 3. Set up the Resolution ************** //// Fairly straightforward - X Y dimensions. Must be at least 1. Don't //// worry about reduced cooking res's - they are handled automatically. // mySequence.setRes(500, 400); // mySequence.setAspectRatio(1.0f); // x/y (ie, 2: pixel is twice as wide as // it is tall) //// 4. Planes & Data formats **************************** //// Set up the actual planes we'll use. We can create up to 4000, but each //// must have a unique plane name. //// if you'd like to call COP2_Generator to setup the res, range, etc., //// but want complete control over the planes yourself, call: // mySequence.clearAllPlanes(); //// which will remove any planes added by COP2_Generator //// To add planes, use: // mySequence.addPlane("name_of_plane", TILE_[format], "name_of_comp",...) //// plane names recognized by Halo: //// getColorPlaneName() //// getAlphaPlaneName() //// getMaskPlaneName() //// getDepthPlaneName() //// getLumPlaneName() //// getBumpPlaneName() //// getPointPlaneName() //// getNormalPlaneName() //// getVelocityPlaneName() //// Other names can be used as well, but other Nodes won't recognize it //// as anything special. //// format can be TILE_INT8, TILE_INT16, TILE_INT32, TILE_FLOAT32. //// To use black/white points for int formats, call setBlackWhitePoints() //// on the returned plane from addPlane(). FP does not support B/W points. //// components - can be anything descriptive (r,g,b, x,y,z, u,v). //// Halo doesn't care about what the component are names at all. //// The number of strings defines the vector size of the plane (up to 4). //// if no components are specified, the plane is assumed to be Scalar. //TIL_Plane *plane; //// FP color plane, vector size 3 with components named r,g,b. //plane = mySequence.addPlane( getColorPlaneName(), TILE_FLOAT32, // "r","g","b"); //// 8 bit alpha plane, scalar. //plane = mySequence.addPlane( getAlphaPlaneName(), TILE_INT8 ); // plane->setBlackWhitePoints(16, 240); // for 8 bit with a bit of // head/foot room, for example //// Some other plane examples: // plane = mySequence.addPlane( getBumpPlaneName(), TILE_INT16, "u","v"); // plane->setBlackWhitePoints(32768, 65535); // dynamic range ~= -1 to 1 // mySequence.addPlane( getDepthPlaneName(), TILE_FLOAT32); // mySequence.addPlane( getPointPlaneName(), TILE_FLOAT32, "x","y","z"); //// ****** End examples ******* // done. return &mySequence; } // ** newContextData() // This method is used to create a custom context for your node. If you need // to evaluate animated parms, do it here and stash the values in your context // data. All context data classes must derive from COP2_ContextData (see .h // file for class def) // If you have all static parms, like menus or toggles, you can evaluate them // in cookSequenceInfo() instead, if you like. // The context data is also useful for holding scratch data arrays. // By default, a context is created for each different time and each different // resolution. You can also cause it to create them if the plane differs, or // the thread differs (if a plane or res variable is used in an expression, it // will automatically create a new context data for you if plane or res // changes). To controls the creation of contexts, override the virtuals: // // virtual bool createPerPlane() const { return false; } // virtual bool createPerRes() const { return true; } // virtual bool createPerTime() const { return true; } // virtual bool createPerThread() const { return false; } // in your custom COP2_ContextData class. COP2_ContextData * COP2_SampleGenerator::newContextData(const TIL_Plane * /*planename*/, int /*arrayindex*/, float t, int /*xsize*/, int /*ysize*/, int /*thread*/, int /*max_num_threads*/) { // create one of my context datas. cop2_SampleGeneratorData *data = new cop2_SampleGeneratorData; // stashing some parm values for the cook in my context data. AMP(data->myAmp, t); data->mySeed = SEED(t); return data; } // ** generateTile() // This method cooks a tile of the full image. A tile is a rectangular region // of the image for a specific component of a specific plane. This means that // all vectors' data is stored non-interleaved, one component per tile. // Before proceeding with your cook, you may need to check the: // - plane you are being requested to cook (context.myPlane) // - the resolution you are being cooked at (context.myXres, context.myYres) // - the time you are being cooked at (context.myTime) // - the area the tile occupies (tiles->myX1, tiles->myY1) - // (tiles->myX2, tiles->myY2) // You may not be asked to cook all the tiles in the image, and you may not // be asked to cook all the planes. Cooking is done on an on-demand basis. // The order you are asked to cook tiles in is undefined. // The TIL_TileList passed to you contains 1-4 tiles, depending on the # of // components in that plane. Some of these components may already be cached, // so use FOR_EACH_UNCOOKED_TILE(tiles, itr) to iterate through only dirty // tiles or TILE_VECTOR4(tiles, t1,t2,t3,t4) to assign the dirty tiles to // TIL_Tile *t1,*t2,*t3,*t4. Non-dirty or non-existant tiles will be assigned // NULL to the TIL_Tile ptr. // Tiles are not pre-cleared for you. You must write to each pixel in the tile. // THREAD WARNING: This method is called simultaneously in different threads. // Don't do un-threadsafe stuff here, like writing to static buffers. OP_ERROR COP2_SampleGenerator::generateTile(COP2_Context &context, TIL_TileList *tiles) { // retrieve my context data created for this plane/res/time/thread // by my newContextData method. cop2_SampleGeneratorData *data = static_cast<cop2_SampleGeneratorData *>( context.data() ); int i, ti; TIL_Tile * itr; unsigned seed; const float *amp = data->myAmp.data(); // alloc some temp space for our values. If we know that we're always using // FP, we could just write the values into the tiles directly using // dest = (float *) itr->getImageData(); float *dest = new float[tiles->mySize]; FOR_EACH_UNCOOKED_TILE(tiles, itr, ti) { // initial seed value based on lower left corner position & tile index. seed = ((unsigned) data->mySeed * 4 + ti) * (context.myXres * context.myYres) + tiles->myX1 + tiles->myY1 * context.myXres; // tiles->mySize is the # of pixels in the tile. for(i=0; i<tiles->mySize; i++) dest[i] = UTrandom(seed) * amp[ti]; // write the values back to the tile using a convenience method. // not necessary if we used dest = (float *) itr->getImageData() above. writeFPtoTile(tiles, dest, ti); } delete dest; return error(); } /// install the cop. void newCop2Operator(OP_OperatorTable *table) { // This operator flags itself as a generator taking zero or one inputs. // The optional input is the mask. table->addOperator(new OP_Operator("hdk_samplegen", // node name "HDK Sample Generator", // pretty name COP2_SampleGenerator::myConstructor, &COP2_SampleGenerator::myTemplatePair, 0, // min inputs 1, // max inputs &COP2_SampleGenerator::myVariablePair, OP_FLAG_GENERATOR)); }
1.5.9