00001 /* 00002 * Copyright (c) 2012 00003 * Side Effects Software Inc. All rights reserved. 00004 * 00005 * Redistribution and use of Houdini Development Kit samples in source and 00006 * binary forms, with or without modification, are permitted provided that the 00007 * following conditions are met: 00008 * 1. Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * 2. The name of Side Effects Software may not be used to endorse or 00011 * promote products derived from this software without specific prior 00012 * written permission. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS 00015 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00017 * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, 00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00019 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00020 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00021 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00022 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 00023 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00024 * 00025 *---------------------------------------------------------------------------- 00026 * This custom object defines a geometry object that has parameters which 00027 * define a frame-dependent jitter in its translation. This can be used to make 00028 * earth-quake type effects. No doubt next year will be the year of the 00029 * Earthquake movie. 00030 */ 00031 00032 #include <UT/UT_DSOVersion.h> 00033 #include <UT/UT_Math.h> 00034 #include <PRM/PRM_Include.h> 00035 #include <OP/OP_Director.h> 00036 #include <OP/OP_OperatorTable.h> 00037 #include "OBJ_Shake.h" 00038 00039 00040 using namespace HDK_Sample; 00041 00042 // shakeIndirect is an array of indices that are used to access parameters 00043 // quickly. The indices are initialized by the EVAL_FLOAT methods in the 00044 // header file. 00045 int *OBJ_Shake::shakeIndirect = 0; 00046 00047 00048 00049 // Constructor for new object class 00050 OBJ_Shake::OBJ_Shake(OP_Network *net, const char *name, OP_Operator *op) 00051 :OBJ_Geometry(net, name, op) 00052 { 00053 // initialize local member data here. 00054 00055 // shakeIndirect is initialized to an array of 3 indices (each initialized 00056 // to -1 -- ie not accessed yet) 00057 if (!shakeIndirect) shakeIndirect = allocIndirect(3); 00058 } 00059 00060 00061 00062 // virtual destructor for new object class 00063 OBJ_Shake::~OBJ_Shake() 00064 { 00065 } 00066 00067 00068 // Un-comment the next line to see an example of creating custom tabs 00069 //#define SWITCHER_EXAMPLE 00070 #ifdef SWITCHER_EXAMPLE 00071 static PRM_Name switcherName("shakeswitcher"); 00072 static PRM_Default switcher[] = { 00073 PRM_Default( 1, "Shake"), // 1 is number of parameters in tab 00074 PRM_Default( 0, "Other"), // actually have no parameters here 00075 }; 00076 #endif 00077 00078 // here is the name of the parameter that is used by the shake object 00079 static PRM_Name OBJjitter("jitter", "Jitter scale"); 00080 00081 00082 00083 // this is the template list that defines the new parameters that are 00084 // used by the shake object. 00085 static PRM_Template templatelist[] = 00086 { 00087 // Here we define the new parameter 00088 #ifdef SWITCHER_EXAMPLE 00089 PRM_Template(PRM_SWITCHER, sizeof(switcher)/sizeof(PRM_Default), 00090 &switcherName, switcher), 00091 #endif 00092 PRM_Template(PRM_XYZ_J, 3, &OBJjitter, PRMoneDefaults), 00093 00094 // followed by this blank terminating Template. 00095 PRM_Template() 00096 }; 00097 00098 00099 00100 // this function returns the OP_TemplatePair that combines the parameters 00101 // of this object with those of its ancestors in the (object type hierarchy) 00102 OP_TemplatePair * 00103 OBJ_Shake::buildTemplatePair(OP_TemplatePair *prevstuff) 00104 { 00105 OP_TemplatePair *shake, *geo; 00106 00107 // Here, we have to "inherit" template pairs from geometry and beyond. To 00108 // do this, we first need to instantiate our template list, then add the 00109 // base class templates. 00110 shake = new OP_TemplatePair(templatelist, prevstuff); 00111 geo = new OP_TemplatePair(OBJ_Geometry::getTemplateList(OBJ_PARMS_PLAIN), 00112 shake); 00113 return geo; 00114 } 00115 00116 00117 00118 // the myConstructor method is used to create new objects of the correct 00119 // type from the OperatorTable. 00120 OP_Node * 00121 OBJ_Shake::myConstructor(OP_Network *net, const char *name, OP_Operator *op) 00122 { 00123 return new OBJ_Shake(net, name, op); 00124 } 00125 00126 00127 00128 // this method pre-multiplies the given matrix with an appropriate transform 00129 // to shake the object. our shake transform gets inserted into the object 00130 // transform pipeline essentially before the transform parameters. 00131 int 00132 OBJ_Shake::applyInputIndependentTransform(OP_Context &context, UT_DMatrix4 &mat) 00133 { 00134 const float t = context.myTime; // extract time from OP_Context 00135 float jx, jy, jz; 00136 unsigned seed; 00137 int modified; 00138 00139 // call OBJ_Geometry::applyInputIndependentTransform() so that we don't 00140 // lose any information 00141 modified = OBJ_Geometry::applyInputIndependentTransform(context, mat); 00142 if (error() >= UT_ERROR_ABORT) 00143 { 00144 // don't do anything since an error has occurred. 00145 return modified; 00146 } 00147 00148 // first we compute our jitter values as a random value within 00149 // the given jitter scale using a frame dependent seed value 00150 // (different for x, y, and z) 00151 jx = JX(t); jy = JY(t); jz = JZ(t); 00152 00153 seed = (int)OPgetDirector()->getChannelManager()->getSample(t); 00154 jx *= 2*UTfastRandom(seed) - 1.0; 00155 00156 seed ^= 0xdeadbeef; 00157 jy *= 2*UTfastRandom(seed) - 1.0; 00158 00159 seed ^= 0xfadedcab; 00160 jz *= 2*UTfastRandom(seed) - 1.0; 00161 00162 // we add our jitter to the object transform 00163 mat.pretranslate(jx, jy, jz); 00164 00165 // return 1 to indicate that we have modified the input matrix. 00166 // if we didn't modify mat, then we should return 0 instead. 00167 return 1; 00168 } 00169 00170 00171 00172 OP_ERROR 00173 OBJ_Shake::cookMyObj(OP_Context &context) 00174 { 00175 OP_ERROR errorstatus; 00176 00177 // OBJ_Geometry::cookMyObj computes the local and global transform, and 00178 // also the inverse of the global transform matrix. These are stored 00179 // in myXform, myWorldXform, and myIWorldXform, respectively. 00180 errorstatus = OBJ_Geometry::cookMyObj(context); 00181 00182 // since the jitter value is frame dependent and this object won't 00183 // be flagged as time dependent through any other method, we explicitly 00184 // flag it here. 00185 // NB: this flag gets reset at the beginning of every cook, unless 00186 // tranform caching is enabled by the object parameter. 00187 // When transforms are cached, this flag is cleared before the cook on 00188 // which there was a miss that invalidated all cached transforms for 00189 // that object. 00190 flags().timeDep = 1; 00191 00192 return errorstatus; 00193 } 00194 00195 00196 00197 // this function installs the new object in houdini's object table. 00198 void 00199 newObjectOperator(OP_OperatorTable *table) 00200 { 00201 table->addOperator(new OP_Operator("hdk_shake", "Shake", 00202 OBJ_Shake::myConstructor, 00203 OBJ_Shake::buildTemplatePair(0), 0, 1, 00204 0)); 00205 }
1.5.9