00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "SOP_CustomBrush.h"
00029
00030 #include <OP/OP_OperatorTable.h>
00031 #include <OP/OP_SaveFlags.h>
00032 #include <PRM/PRM_Include.h>
00033 #include <UT/UT_CPIO.h>
00034 #include <UT/UT_DSOVersion.h>
00035 #include <UT/UT_IStream.h>
00036 #include <UT/UT_StreamFilter.h>
00037 #include <UT/UT_Undo.h>
00038 #include <UT/UT_UndoManager.h>
00039
00040
00041 namespace HDK_Sample {
00042 class SOP_UndoCustomBrushData : public UT_Undo
00043 {
00044 public:
00045 SOP_UndoCustomBrushData(SOP_CustomBrush *sop,
00046 int oldnumpts,
00047 int numpts,
00048 UT_RefArray<SOP_CustomBrushData> &olddata,
00049 UT_RefArray<SOP_CustomBrushData> &data);
00050
00051 virtual void undo();
00052 virtual void redo();
00053
00054 private:
00055 int mySopId;
00056 int myOldNumPts;
00057 int myNumPts;
00058 UT_RefArray<SOP_CustomBrushData> myOldData;
00059 UT_RefArray<SOP_CustomBrushData> myData;
00060 };
00061 }
00062 using namespace HDK_Sample;
00063
00064 SOP_UndoCustomBrushData::SOP_UndoCustomBrushData(
00065 SOP_CustomBrush *sop,
00066 int oldnumpts,
00067 int numpts,
00068 UT_RefArray<SOP_CustomBrushData> &olddata,
00069 UT_RefArray<SOP_CustomBrushData> &data) :
00070 mySopId(sop->getUniqueId()),
00071 myOldNumPts(oldnumpts),
00072 myNumPts(numpts),
00073 myOldData(olddata),
00074 myData(data)
00075 {
00076
00077
00078 addToMemoryUsage(olddata.getMemoryUsage() + data.getMemoryUsage());
00079 }
00080
00081 void
00082 SOP_UndoCustomBrushData::undo()
00083 {
00084 SOP_CustomBrush *node = (SOP_CustomBrush *)OP_Node::lookupNode(mySopId);
00085 node->updateData(myOldNumPts, myOldData);
00086 }
00087
00088 void
00089 SOP_UndoCustomBrushData::redo()
00090 {
00091 SOP_CustomBrush *node = (SOP_CustomBrush *)OP_Node::lookupNode(mySopId);
00092 node->updateData(myNumPts, myData);
00093 }
00094
00095 void
00096 newSopOperator(OP_OperatorTable *table)
00097 {
00098 table->addOperator(new OP_Operator("proto_custombrush", "Custom Brush",
00099 SOP_CustomBrush::myConstructor,
00100 SOP_CustomBrush::myTemplateList,
00101 1, 1));
00102 }
00103
00104 static PRM_Name sopOriginName("origin", "Origin");
00105 static PRM_Name sopDirectionName("direction", "Direction");
00106 static PRM_Name sopRadiusName("radius", "Radius");
00107 static PRM_Name sopColorName("color", "Color");
00108 static PRM_Name sopAlphaName("alpha", "Alpha");
00109 static PRM_Name sopOperationName("operation", "Operation");
00110 static PRM_Name sopEventName("event", "Event");
00111 static PRM_Name sopClearAllName("clearall", "Clear All");
00112
00113 enum SOP_CustomBrushOperation
00114 {
00115 SOP_CUSTOMBRUSHOPERATION_PAINT,
00116 SOP_CUSTOMBRUSHOPERATION_ERASE
00117 };
00118
00119 static PRM_Name sopOperationMenuNames[] =
00120 {
00121 PRM_Name("paint", "Paint"),
00122 PRM_Name("erase", "Erase"),
00123 PRM_Name(0)
00124 };
00125 static PRM_ChoiceList sopOperationMenu(PRM_CHOICELIST_SINGLE, sopOperationMenuNames);
00126 static PRM_Default sopOperationDefault(SOP_CUSTOMBRUSHOPERATION_PAINT);
00127
00128 enum SOP_CustomBrushEvent
00129 {
00130 SOP_CUSTOMBRUSHEVENT_BEGIN,
00131 SOP_CUSTOMBRUSHEVENT_ACTIVE,
00132 SOP_CUSTOMBRUSHEVENT_END,
00133 SOP_CUSTOMBRUSHEVENT_NOP
00134 };
00135
00136 static PRM_Name sopEventMenuNames[] =
00137 {
00138 PRM_Name("begin", "Begin Stroke"),
00139 PRM_Name("active", "Active Stroke"),
00140 PRM_Name("end", "End Stroke"),
00141 PRM_Name("nop", "No-op"),
00142 PRM_Name(0)
00143 };
00144 static PRM_ChoiceList sopEventMenu(PRM_CHOICELIST_SINGLE, sopEventMenuNames);
00145 static PRM_Default sopEventDefault(SOP_CUSTOMBRUSHEVENT_NOP);
00146
00147 PRM_Template
00148 SOP_CustomBrush::myTemplateList[] = {
00149 PRM_Template(PRM_STRING, 1, &PRMgroupName, 0, &SOP_Node::pointGroupMenu),
00150 PRM_Template(PRM_XYZ_J, 3, &sopOriginName),
00151 PRM_Template(PRM_XYZ_J, 3, &sopDirectionName),
00152 PRM_Template(PRM_FLT_J, 1, &sopRadiusName, PRMoneDefaults),
00153 PRM_Template(PRM_RGB_J, 3, &sopColorName, PRMoneDefaults),
00154 PRM_Template(PRM_FLT_J, 1, &sopAlphaName, PRMpointOneDefaults),
00155 PRM_Template(PRM_ORD, 1, &sopOperationName, &sopOperationDefault,
00156 &sopOperationMenu),
00157 PRM_Template(PRM_ORD, 1, &sopEventName, &sopEventDefault, &sopEventMenu),
00158 PRM_Template(PRM_CALLBACK, 1, &sopClearAllName, 0, 0, 0, &clearAllStatic),
00159 PRM_Template()
00160 };
00161
00162 OP_Node *
00163 SOP_CustomBrush::myConstructor(OP_Network *net, const char *name, OP_Operator *op)
00164 {
00165 return new SOP_CustomBrush(net, name, op);
00166 }
00167
00168 SOP_CustomBrush::SOP_CustomBrush(OP_Network *net, const char *name, OP_Operator *op) :
00169 SOP_Node(net, name, op),
00170 myGroup(0),
00171 myNumPts(0),
00172 myOldNumPts(0)
00173 {
00174 }
00175
00176 SOP_CustomBrush::~SOP_CustomBrush()
00177 {
00178 }
00179
00180 OP_ERROR
00181 SOP_CustomBrush::cookInputGroups(OP_Context &context, int alone)
00182 {
00183 const GB_PointGroup *grp = 0;
00184 OP_ERROR err = cookInputPointGroups(context, grp,
00185 myDetailGroupPair, alone);
00186 if(!alone)
00187 myGroup = grp;
00188
00189 return err;
00190 }
00191
00192 OP_ERROR
00193 SOP_CustomBrush::cookMySop(OP_Context &context)
00194 {
00195
00196
00197 if (lockInputs(context) < UT_ERROR_ABORT)
00198 {
00199 fpreal t = context.myTime;
00200
00201
00202
00203 int changed_input;
00204 duplicateChangedSource(0, context, &changed_input);
00205
00206 if (cookInputGroups(context) >= UT_ERROR_ABORT)
00207 {
00208 unlockInputs();
00209 return error();
00210 }
00211
00212 int npts = gdp->points().entries();
00213
00214 if(myData.entries() == 0)
00215 {
00216
00217
00218 myNumPts = npts;
00219 }
00220 else if(myNumPts != npts)
00221 {
00222
00223 addError(SOP_ERR_MISMATCH_POINT);
00224 unlockInputs();
00225 return error();
00226 }
00227
00228 int event = getEvent(t);
00229 if(event == SOP_CUSTOMBRUSHEVENT_BEGIN)
00230 {
00231
00232 myOldData.entries(0);
00233 myOldNumPts = myNumPts;
00234 }
00235 else if(event == SOP_CUSTOMBRUSHEVENT_ACTIVE)
00236 {
00237
00238 UT_Vector3 origin = getOrigin(t);
00239 UT_Vector3 direction = getDirection(t);
00240 direction.normalize();
00241 fpreal radius = getRadius(t);
00242 fpreal radius2 = radius * radius;
00243 fpreal alpha = getAlpha(t);
00244 UT_Vector3 color = getColor(t);
00245 int operation = getOperation(t);
00246
00247
00248
00249 UT_HashTable table;
00250 for(int i = 0; i < myData.entries(); ++i)
00251 table.addSymbol(UT_Hash_Int(myData(i).myPtNum), UT_Thing(i));
00252 UT_HashTable oldtable;
00253 for(int i = 0; i < myOldData.entries(); ++i)
00254 oldtable.addSymbol(UT_Hash_Int(myOldData(i).myPtNum), UT_Thing(i));
00255
00256 const GEO_Point *pt;
00257 FOR_ALL_OPT_GROUP_POINTS(gdp, myGroup, pt)
00258 {
00259
00260
00261 UT_Vector3 pos = pt->getPos();
00262
00263 UT_Vector3 p = pos - origin;
00264 p.normalize();
00265 fpreal dot_p_dir = dot(p, direction);
00266 if(dot_p_dir > 0)
00267 {
00268 UT_Vector3 par = dot_p_dir * direction;
00269 UT_Vector3 perp = p - par;
00270
00271 fpreal parlen2 = dot_p_dir * dot_p_dir;
00272 if(parlen2 > 0 && perp.length2() < radius2 * parlen2)
00273 {
00274
00275 int ptnum = pt->getNum();
00276 UT_Hash_Int hashkey(ptnum);
00277 UT_Thing thing;
00278
00279
00280 if(!table.findSymbol(hashkey, &thing))
00281 {
00282
00283 thing = (long)myData.entries();
00284 myData.append(SOP_CustomBrushData(ptnum, 0, 0, 0, 0));
00285 table.addSymbol(hashkey, thing);
00286 }
00287 SOP_CustomBrushData &d = myData((long)thing);
00288
00289 if(!oldtable.findSymbol(hashkey, &thing))
00290 {
00291
00292 thing = (long)myOldData.entries();
00293 myOldData.append(d);
00294 oldtable.addSymbol(hashkey, thing);
00295 }
00296
00297
00298 fpreal one_minus_alpha = 1 - alpha;
00299 switch(operation)
00300 {
00301 case SOP_CUSTOMBRUSHOPERATION_PAINT:
00302 d.myRed = alpha * color.x() + one_minus_alpha * d.myRed;
00303 d.myGreen = alpha * color.y() + one_minus_alpha * d.myGreen;
00304 d.myBlue = alpha * color.z() + one_minus_alpha * d.myBlue;
00305 d.myAlpha = alpha + one_minus_alpha * d.myAlpha;
00306 break;
00307
00308 case SOP_CUSTOMBRUSHOPERATION_ERASE:
00309 d.myRed *= one_minus_alpha;
00310 d.myGreen *= one_minus_alpha;
00311 d.myBlue *= one_minus_alpha;
00312 d.myAlpha *= one_minus_alpha;
00313 break;
00314 }
00315 }
00316 }
00317 }
00318 }
00319 else if(event == SOP_CUSTOMBRUSHEVENT_END)
00320 {
00321
00322 UT_UndoManager *man = UTgetUndoManager();
00323 if(man->willAcceptUndoAddition())
00324 {
00325
00326 man->addToUndoBlock(new SOP_UndoCustomBrushData(this, myOldNumPts, myNumPts, myOldData, myData));
00327 myOldData.entries(0);
00328 }
00329 }
00330
00331
00332 const GU_Detail *input0 = inputGeo(0);
00333 int input_offset = input0->findPointAttrib(GEO_STD_ATTRIB_DIFFUSE,
00334 3 * sizeof(float), GB_ATTRIB_FLOAT);
00335
00336
00337
00338 int offset = gdp->findPointAttrib(GEO_STD_ATTRIB_DIFFUSE,
00339 3 * sizeof(float), GB_ATTRIB_FLOAT);
00340 if(offset < 0)
00341 {
00342 offset = gdp->addPointAttrib(GEO_STD_ATTRIB_DIFFUSE,
00343 3 * sizeof(float), GB_ATTRIB_FLOAT, 0);
00344 }
00345 if(offset >= 0)
00346 {
00347
00348 for(int i = 0; i < myData.entries(); ++i)
00349 {
00350 SOP_CustomBrushData &data = myData(i);
00351
00352 fpreal r = data.myRed;
00353 fpreal g = data.myGreen;
00354 fpreal b = data.myBlue;
00355 if(input_offset >= 0)
00356 {
00357 fpreal one_minus_alpha = 1 - data.myAlpha;
00358 const GEO_Point *pt = input0->points()(data.myPtNum);
00359 const float *f = pt->castAttribData<float>(input_offset);
00360 r += one_minus_alpha * f[0];
00361 g += one_minus_alpha * f[1];
00362 b += one_minus_alpha * f[2];
00363 }
00364
00365 GEO_Point *pt = gdp->points()(data.myPtNum);
00366 float *f = pt->castAttribData<float>(offset);
00367 f[0] = r;
00368 f[1] = g;
00369 f[2] = b;
00370 }
00371 }
00372
00373 unlockInputs();
00374 }
00375 return error();
00376 }
00377
00378 OP_ERROR
00379 SOP_CustomBrush::save(
00380 ostream &os,
00381 const OP_SaveFlags &saveflags,
00382 const char *path_prefix)
00383 {
00384 if(SOP_Node::save(os, saveflags, path_prefix) >= UT_ERROR_ABORT)
00385 return error();
00386
00387
00388 UT_CPIO packet;
00389 UT_WorkBuffer path;
00390 const char *ext = saveflags.getBinary() ? "bpaint" : "paint";
00391 path.sprintf("%s%s.%s", path_prefix, (const char *)getName(), ext);
00392 packet.open(os, path.buffer());
00393 UT_OStreamFilter filter(os, saveflags.getBinary());
00394
00395 filter.write(myNumPts);
00396 filter.endLine();
00397
00398 int n = myData.entries();
00399 filter.write(n);
00400 filter.endLine();
00401
00402 for(int i = 0; i < n; ++i)
00403 {
00404 SOP_CustomBrushData &data = myData(i);
00405 filter.write(data.myPtNum);
00406 filter.write(data.myRed);
00407 filter.write(data.myGreen);
00408 filter.write(data.myBlue);
00409 filter.write(data.myAlpha);
00410 }
00411 filter.endLine();
00412
00413 packet.close(os);
00414
00415 return error();
00416 }
00417
00418 bool
00419 SOP_CustomBrush::load(UT_IStream &is, const char *ext, const char *path)
00420 {
00421
00422 if(strcmp(ext, "bpaint") == 0 || strcmp(ext, "paint") == 0)
00423 {
00424 myNumPts = 0;
00425 myData.entries(0);
00426 myOldData.entries(0);
00427
00428 if(!is.read(&myNumPts))
00429 return false;
00430
00431 int n;
00432 if(!is.read(&n))
00433 return false;
00434 for(int i = 0; i < n; ++i)
00435 {
00436 int idx;
00437 if(!is.read(&idx))
00438 return false;
00439
00440 float r;
00441 if(!is.read(&r))
00442 return false;
00443
00444 float g;
00445 if(!is.read(&g))
00446 return false;
00447
00448 float b;
00449 if(!is.read(&b))
00450 return false;
00451
00452 float a;
00453 if(!is.read(&a))
00454 return false;
00455
00456 myData.append(SOP_CustomBrushData(idx, r, g, b, a));
00457 }
00458
00459 return true;
00460 }
00461
00462 return SOP_Node::load(is, ext, path);
00463 }
00464
00465 void
00466 SOP_CustomBrush::updateData(int numpts, UT_RefArray<SOP_CustomBrushData> &data)
00467 {
00468 myNumPts = numpts;
00469 if(myNumPts == 0)
00470 {
00471 myData.entries(0);
00472
00473
00474
00475
00476
00477 resetChangedSourceFlags();
00478 }
00479 else
00480 {
00481
00482
00483 UT_HashTable table;
00484 for(int i = 0; i < myData.entries(); ++i)
00485 table.addSymbol(UT_Hash_Int(myData(i).myPtNum), UT_Thing(i));
00486
00487 for(int i = 0; i < data.entries(); ++i)
00488 {
00489 SOP_CustomBrushData &d = data(i);
00490 UT_Hash_Int hashkey(d.myPtNum);
00491
00492 UT_Thing thing;
00493 if(table.findSymbol(hashkey, &thing))
00494 {
00495
00496
00497 myData((long)thing) = d;
00498 }
00499 else
00500 {
00501
00502 thing = (long)myData.entries();
00503 myData.append(d);
00504 table.addSymbol(hashkey, thing);
00505 }
00506 }
00507 }
00508
00509
00510 forceRecook();
00511 }
00512
00513 int
00514 SOP_CustomBrush::clearAllStatic(void *op, int, float time, const PRM_Template *)
00515 {
00516 SOP_CustomBrush *sop = (SOP_CustomBrush *)op;
00517 sop->clearAll();
00518 return 1;
00519 }
00520
00521 void
00522 SOP_CustomBrush::clearAll()
00523 {
00524 UT_AutoUndoBlock undoblock("Clear All", ANYLEVEL);
00525
00526 int oldnumpts = myNumPts;
00527 myNumPts = 0;
00528 myOldData = myData;
00529 myData.entries(0);
00530
00531 UT_UndoManager *man = UTgetUndoManager();
00532 if(man->willAcceptUndoAddition())
00533 {
00534 man->addToUndoBlock(new SOP_UndoCustomBrushData(this, oldnumpts, myNumPts, myOldData, myData));
00535 myOldData.entries(0);
00536 }
00537
00538
00539
00540
00541
00542 resetChangedSourceFlags();
00543 forceRecook();
00544 }