/* * 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. * *---------------------------------------------------------------------------- * This custom object defines a geometry object that has parameters which * define a frame-dependent jitter in its translation. This can be used to make * earth-quake type effects. No doubt next year will be the year of the * Earthquake movie. */ #include <UT/UT_DSOVersion.h> #include <UT/UT_Math.h> #include <PRM/PRM_Include.h> #include <OP/OP_Director.h> #include <OP/OP_OperatorTable.h> #include "OBJ_Shake.h" using namespace HDK_Sample; // shakeIndirect is an array of indices that are used to access parameters // quickly. The indices are initialized by the EVAL_FLOAT methods in the // header file. int *OBJ_Shake::shakeIndirect = 0; // Constructor for new object class OBJ_Shake::OBJ_Shake(OP_Network *net, const char *name, OP_Operator *op) :OBJ_Geometry(net, name, op) { // initialize local member data here. // shakeIndirect is initialized to an array of 3 indices (each initialized // to -1 -- ie not accessed yet) if (!shakeIndirect) shakeIndirect = allocIndirect(3); } // virtual destructor for new object class OBJ_Shake::~OBJ_Shake() { } // Un-comment the next line to see an example of creating custom tabs //#define SWITCHER_EXAMPLE #ifdef SWITCHER_EXAMPLE static PRM_Name switcherName("shakeswitcher"); static PRM_Default switcher[] = { PRM_Default( 1, "Shake"), // 1 is number of parameters in tab PRM_Default( 0, "Other"), // actually have no parameters here }; #endif // here is the name of the parameter that is used by the shake object static PRM_Name OBJjitter("jitter", "Jitter scale"); // this is the template list that defines the new parameters that are // used by the shake object. static PRM_Template templatelist[] = { // Here we define the new parameter #ifdef SWITCHER_EXAMPLE PRM_Template(PRM_SWITCHER, sizeof(switcher)/sizeof(PRM_Default), &switcherName, switcher), #endif PRM_Template(PRM_XYZ_J, 3, &OBJjitter, PRMoneDefaults), // followed by this blank terminating Template. PRM_Template() }; // this function returns the OP_TemplatePair that combines the parameters // of this object with those of its ancestors in the (object type hierarchy) OP_TemplatePair * OBJ_Shake::buildTemplatePair(OP_TemplatePair *prevstuff) { OP_TemplatePair *shake, *geo; // Here, we have to "inherit" template pairs from geometry and beyond. To // do this, we first need to instantiate our template list, then add the // base class templates. shake = new OP_TemplatePair(templatelist, prevstuff); geo = new OP_TemplatePair(OBJ_Geometry::getTemplateList(OBJ_PARMS_PLAIN), shake); return geo; } // the myConstructor method is used to create new objects of the correct // type from the OperatorTable. OP_Node * OBJ_Shake::myConstructor(OP_Network *net, const char *name, OP_Operator *op) { return new OBJ_Shake(net, name, op); } // this method pre-multiplies the given matrix with an appropriate transform // to shake the object. our shake transform gets inserted into the object // transform pipeline essentially before the transform parameters. int OBJ_Shake::applyInputIndependentTransform(OP_Context &context, UT_DMatrix4 &mat) { const float t = context.getTime(); // extract time from OP_Context float jx, jy, jz; unsigned seed; int modified; // call OBJ_Geometry::applyInputIndependentTransform() so that we don't // lose any information modified = OBJ_Geometry::applyInputIndependentTransform(context, mat); if (error() >= UT_ERROR_ABORT) { // don't do anything since an error has occurred. return modified; } // first we compute our jitter values as a random value within // the given jitter scale using a frame dependent seed value // (different for x, y, and z) jx = JX(t); jy = JY(t); jz = JZ(t); seed = (int)OPgetDirector()->getChannelManager()->getSample(t); jx *= 2*UTfastRandom(seed) - 1.0; seed ^= 0xdeadbeef; jy *= 2*UTfastRandom(seed) - 1.0; seed ^= 0xfadedcab; jz *= 2*UTfastRandom(seed) - 1.0; // we add our jitter to the object transform mat.pretranslate(jx, jy, jz); // return 1 to indicate that we have modified the input matrix. // if we didn't modify mat, then we should return 0 instead. return 1; } OP_ERROR OBJ_Shake::cookMyObj(OP_Context &context) { OP_ERROR errorstatus; // OBJ_Geometry::cookMyObj computes the local and global transform, and // also the inverse of the global transform matrix. These are stored // in myXform, myWorldXform, and myIWorldXform, respectively. errorstatus = OBJ_Geometry::cookMyObj(context); // since the jitter value is frame dependent and this object won't // be flagged as time dependent through any other method, we explicitly // flag it here. // NB: this flag gets reset at the beginning of every cook, unless // tranform caching is enabled by the object parameter. // When transforms are cached, this flag is cleared before the cook on // which there was a miss that invalidated all cached transforms for // that object. flags().timeDep = 1; return errorstatus; } // this function installs the new object in houdini's object table. void newObjectOperator(OP_OperatorTable *table) { table->addOperator(new OP_Operator("hdk_shake", "Shake", OBJ_Shake::myConstructor, OBJ_Shake::buildTemplatePair(0), 0, 1, 0)); }
1.5.9