Showing posts with label Shake. Show all posts
Showing posts with label Shake. Show all posts

Sunday, May 24, 2009

NRiHook

I haven't added an entry for a while so this is just a copy&paste from my hidden blog which tells you how to use Shake's NRiHook. This entry is just for telling you that I'm not dead ;)


class TamHook : public NRiHook
{
public:
TamHook(NRiNode *hNode, const NRiName &hName):NRiHook(hNode, hName){}
virtual void notify (Event e, void *n);
};

void TamHook::notify(Event e, void *n)
{
NRiSys::error("TamHook::notify called.\n");
}

TamHook* t;
NRiNode* node = NRiNode::findNode("NRiScript1.foo");
t = new TamHook(node, "tamtam");


You can see what has happened to "foo" by looking at the 'Event' object passed as an argument. Take care of memory management (Make sure you delete a hook which is not used any more) when you use it.

I tried to show an working example from one of my plugins but it was way way too complicated to copy it here. Please let me know if you happen to be interested.

Sunday, November 2, 2008

So how do I use Shake Command Window?

I use it for plug-in development. You don't have to restart Shake every time you modify a code. You can see the internal state of nodes interactively, you can test your plug-in after modifying the node state, and you can see how things work, monitor plug changes to see if node evaluation chain is working as you expected. There are two programs I was mainly using. I made these two programs bit by bit interactively with the Command Window.

[dispTree] Displays a node tree.
name: the root tree
recurseNode: set true if you want to show child node
showPlug: set true if you also want to show plugs and their values
recursePlug: set true if you want to show child plugs and their values

























[dispPlugInfo] displays informations about a plug
nodename: node name which has the plug to display
plugname: plug name to display



























You may need to add include directives to the header include (settings - header include).
#include <string>, etc.

[dispTree]


const char* name = "NRiScript1";
bool recurseNode = true;
bool showPlug = false;
bool recursePlug = false;

#define print(x) NRiSys::error((NRiName() + x).getString());

const NRiName operator +(const NRiName lhs, const std::string rhs)
{
return lhs + rhs.c_str();
}

void printSpace(int nestcount)
{
for (int n = 0; n < nestcount; ++n)
{
print(" ");
}
}


void dispPlug(NRiPlug* p)
{
NRiName val;
switch(p->getType())
{
case kString:
val = p->asString();
break;
case kInt:
val = p->asInt();
break;
case kFloat:
val = p->asFloat();
break;
case kDouble:
val = p->asDouble();
break;
case kPtr:
val.sprintf("0x%x", p->asPtr());
break;
default:
break;
}
print(".." + p->getName() + "=" + val + "\n");
}

void dispPlugTree(NRiPlug* plug, int nestcount, bool recursePlug)
{
printSpace(nestcount);
dispPlug(plug);
if (recursePlug)
{
int ncp = plug->getNbChildren();
for (int i = 0; i < ncp; ++i)
{
dispPlugTree(plug->getNthChild(i), nestcount + 1, recursePlug);
}
}
}

void dispNodeTree(NRiNode* node, int nestcount, bool showPlug, bool recurseNode = false, bool recursePlug = false)
{
printSpace(nestcount);
print(node->getName() + ":" + node->getClassName() + "\n");
if (showPlug)
{
int np = node->getNbPlugs();
for (int ip = 0; ip < np; ++ip)
{
dispPlugTree(node->getNthPlug(ip), nestcount + 1, recursePlug);
}
}

if (recurseNode)
{
int numkids = node->getNbChildren();
for (int i = 0; i < numkids; ++i)
{
dispNodeTree(node->getNthChild(i), nestcount + 1, showPlug, recurseNode, recursePlug);
}
}
}

void shakeCommandWinEntryFunc()
{
NRiNode* node = NRiNode::findNode(name);
dispNodeTree(node, 0, showPlug, recurseNode, recursePlug);
}

[dispPlugInfo]

const char* nodename = "NRiScript1.Gamma1";
const char* plugname = "In";


#define print(x) NRiSys::error((NRiName() + x).getString());


NRiName value(NRiPlug* p)
{
NRiName val;
switch(p->getType())
{
case kString:
val = p->asString();
break;
case kInt:
val = p->asInt();
break;
case kFloat:
val = p->asFloat();
break;
case kDouble:
val = p->asDouble();
break;
case kPtr:
val.sprintf("0x%x", p->asPtr());
break;
default:
break;
}
return val;
}

NRiName ioString(NRiPlug* p)
{
const char* types[] = {"ng", "in", "out", "inout"};
return types[p->getIO()];
}

NRiName typeString(NRiPlug* p)
{
switch(p->getType())
{
case kInt:
return "int";
case kFloat:
return "float";
case kPtr:
return "ptr";
case kString:
return "string";
default:
return "ng";
}
}

NRiName flagString(NRiPlug* p)
{
NRiPlug::Flags flags[] = {NRiPlug::kInternal, NRiPlug::kNotify, NRiPlug::kNotifyConnect,
NRiPlug::kInherit, NRiPlug::kDisconnectOnSet, NRiPlug::kPersistent,
NRiPlug::kRecompile, NRiPlug::kLoadable, NRiPlug::kPreUpdate,
NRiPlug::kOwnerScope, NRiPlug::kIgnoreConnect, NRiPlug::kAutoPlug,
NRiPlug::kLocal, NRiPlug::kIgnoreDependencies, NRiPlug::kDeleting,
NRiPlug::kXReadWrite, NRiPlug::kIgnoreType, NRiPlug::kAlwaysCallOwner,
NRiPlug::kMonitor, NRiPlug::kNoExpr, NRiPlug::kInterrupt, NRiPlug::kFiltered,
NRiPlug::kSerializeChildren, NRiPlug::kLookupSrc, NRiPlug::kExpressionSrc,
NRiPlug::kUserDefined, NRiPlug::kPassThrough, NRiPlug::kCurveDefined,
NRiPlug::kLocked};

const char* flagStrings[] = {
"Internal", "Notify", "NotifyConnect", "Inherit", "DisconnectOnSet",
"Persistent", "Recompile", "Loadable", "PreUpdate", "OwnerScope",
"IgnoreConnect", "AutoPlug", "Local", "IgnoreDependencies", "Deleting",
"XReadWrite", "IgnoreType", "AlwaysCallOwner", "Monitor", "NoExpr",
"Interrupt", "Filtered", "SerializeChildren", "LookupSrc", "ExpressionSrc",
"UserDefined", "PassThrough", "CurveDefined", "Locked"};
NRiName result;
for (int i = 0; i < 29; ++i)
{
if (p->getFlag(flags[i]))
{
result += flagStrings[i];
result += " ";
}
}
return result;
}

NRiName hasErrorString(NRiPlug* p)
{
if (p->hasError())
{
return "Yes";
}
else
{
return "No";
}
}

void printPlug(NRiPlug* p)
{
if (p)
{
print(p->getOwner()->getFullName() + ".." + p->getFullName());
}
print("\n");
}

void printPA(const NRiPArray < NRiPlug >& pa)
{
for(unsigned i = 0; i < pa.getLength(); ++i)
{
print(" ");
printPlug(pa[i]);
}
}

void shakeCommandWinEntryFunc()
{
NRiNode* node = NRiNode::findNode(nodename);
if ( ! node)
{
print("Node not found.\n");
return;
}
NRiPlug* plug = node->getPlug(plugname);
if ( ! plug)
{
print("Plug not found.\n");
return;
}

print("<<<");
print(node->getFullName() + ".." + plug->getFullName() + ">>>\n");
print(NRiName() + "[Value] " + value(plug) + "\n");
print(NRiName() + "[Expr] " + plug->asExpr() + "\n");
print(NRiName() + "[IO] " + ioString(plug) + "\n");
print(NRiName() + "[Type] " + typeString(plug) + "\n");
print(NRiName() + "[Flags] " + flagString(plug) + "\n");
print(NRiName() + "[HasError] " + hasErrorString(plug) + "\n");
print("[Input] ");
printPlug(plug->getInput());
print("[LogicalInput] ");
printPlug(plug->getLogicalInput());
//print("[Ouput] ");
//printPlug(plug->getOutput());
print("[Outputs]...\n");
NRiPArray < NRiPlug > pa;
plug->getOutputs(pa);
printPA(pa);
pa.clear();
print("[getLogicalOutputs]...\n");
plug->getLogicalOutputs(pa);
printPA(pa);
pa.clear();
print("[getDependencies]...\n");
const NRiPArray < NRiPlug > * pap;
pap = plug->getDependencies();
printPA(*pap);
print("[getDependents]...\n");
pap = plug->getDependents();
printPA(*pap);
}

Wednesday, October 29, 2008

Shake Command Window ver. 0.94

As I wrote looong time ago, I released ShakeCommandWindow 0.94

New features are:

- Open window by pressing macro button
- At-least-not-crash level fail safe on pointer/floating point/pipe related runtime errors (1)
- Fix freeze bug when pressing macro button while settings panel is open
- Fix freeze bug when trying to display non-ascii string
- Created settings dialog (2)
- Modified default gcc header/footer includes

1.
I signal trapped inside the SCW plug-in so now it doesn't crash when your gcc code has a null-pointer bug, /0 bug, etc. This is not perfect, because newer gcc compilers do not let me raise an exception inside the signal handler, class destructors are not called property, it will probably cause memory leaks and some other side effects. That's why I call it At-least-not-crash level fail safe. But I was happy with this when I was using SCW to make another plug-in.

2.
For unknown reason, my wxPython wouldn't work anymore when a button is in a tab, so I made a separate settings dialog and "settings" button to open the dialog.


You can download it here.

Wednesday, July 30, 2008

Ghost (plug-in demo)

I made a demo for the plug-in. (The actor is me ;)

Click to see the movie























Making:

First I customized texPPattrMapperNode so that it takes camera world matrix, wrote a per particle expression, and made something like this. Particles which background are whiter move faster.



Then I made this in Shake, by ...difference from bg image...blur...contrast...brabrabra.



I connected Maya and Shake with this

(x8)

Sunday, July 27, 2008

Integrating Maya and Shake

In Houdini 3D and 2D composite features are packed in one software but most 3D software has no composite functionalities. I think it is not natural, it hasn't become a big problem but there is no reason they cannot be in one package. Having them in the same place will be good not only for smooth image data transfer but mixing 2D and 3D functionalities to generate one image (composite an image, send it to 3D to build a 3D object which has the shape similar to what's on the image, render it in 3D, composite it with other images, pass it to 3D again to make the image as a source of particle, ... ). Though not as good as Houdini, I thought if I could integrate these two softwares with my Maya and Shake, and I made an experimental system.


(Click to see a movie)
































Internally It is implemented on a generic Shake node which behavior is determined by Python scripts. It is similar to PythonNode in pyshake but higher abstraction level and less generic.























Manual and reference.
http://www.asahi-net.or.jp/~iy7k-tmr/ShakeMayaRender/index.html

summary.
http://www.asahi-net.or.jp/%7Eiy7k-tmr/ShakeMayaRender/summary.html

Sunday, June 29, 2008

Shake Command Window Release 0.94 preannouncement

Release 0.94 preannouncement:
- Open window by pressing macro button
- At-least-not-crash level fail safe on pointer/floating point/pipe related runtime errors
- Fix freeze bug when pressing macro button while settings panel is open
- Fix freeze bug when trying to display non-ascii string
- Maybe it'll come with several utility functions.

These are already implemented. I need to pack it in a new release and write docs for them

Thursday, June 19, 2008

Testing pyshake

It's working O.K. (though it displays an error due to command window's bug). It's good to know that NRiNode and NRiPlug are wrapped, including static methods.
NRiSys::error() is not wrapped (probably because it has variable number of args), so I cannot print messages on the history area. Making a print function by myself will be much easier than modifying py++ or gccxml. I'll make it when I need it.

Saturday, June 7, 2008

Shake Command Window Doc

See also, So how do I use Shake Command Window?

Shake command window (SCW) is a Maya script editor like command window with which you can write and execute a script interactively. It also lets you write a plug-in code in C++ and SCW does everything (save the source to file, compile/link, load, execute, unload, delete files) for you. Shake's console message is redirected to the UI.


Running three types of codes (pyshake, Shake script, gcc)



Compatibility

Currently it only works on Mac OSX 10.5. (Maybe it works on 10.3 and 10.4 if you install the latest wxPython and Python2.5 if they are not installed yet, but I don't have test environment so I cannot say for sure)

Download
Link
Oct. 29th, added.
Please see also this comment for release 0.94


Release 0.942 (bug fix version of 0.94)
Release 0.94
Release 0.93
Release 0.92
Release 0.91
Release 0.9
Release 0.8

When you load the tool, you'll see an option in the File menu. If you select it, SCW's main window will pop up.
















The upper area of the UI is history, where every Shake console message, and SCW's messages are displayed here. Lower area has four tabs. script tab is where you can write Shake script, and gcc tab is where you can write C++ plug-in code. pyshake tab is where you can write Python script (new in version 0.9). It is only available when pyshake is installed on your machine. settings tab is for tool settings. To execute Shake script, Python script, or C++ plug-in code, simply write the script/code and press a button in the Other tab in Shake.








When the script tab is open, the script written in the tab gets executed, and when gcc tab is open, the code gets executed, so does Python script.
settings tab has many buttons and text controls layouted nicely.












erase temporary files after using
If not selected, no temporary files are deleted after execution.
add script It affects how to tread a Shake script. If it is selected, it treats the script like you select File-Add Script... in the Shake menu and load the script. If it is not selected, it is directly passed to Shake's compiler (NRiCmplr). In most cases, leaving it on will do but if you need to turn it off to use extern declaration
show command It just copies a script/code to be executed to the history.
makefile Show Makefile. SCW uses the makefile to compile the plug-in code. Editable
show shell log Standard input/error message when compiling the code using the Makefile. Read only
unload after exec Unload the plug-in from Shake's process after execution.
header include/footer includeThese texts are added to the plug-in code. Editable.
Text area 1 (defaluts to "shakeCommandWinEntryFunc")
When loading the plug-in, SCW tries to search this symbol and execute it
Text area 2 (defaluts to 12) Font size
clear history
Clear the history area
save settings Save all these settings to file. Next time you open SCW, the settings will be loaded automatically

Currently it only works on Mac. I don't have Linux Shake so I can't make it for it but I tried not to use Mac specific things so it won't be difficult to port it.

Please leave a comment here if you like it (or not).



screen capture (using pyshake)

Friday, June 6, 2008

Added background gcc compile functionality to Shake Command Win

O.K. I could add an additional feature to Shake Command Window.
This time you can write a plug-in source code directly in the text field and this tool does the following things for you.
1) compile it using gcc
2) load it in shake
3) execute it
4) (optionally) unload it from shake
5) (optionally) delete files used for the execution














These are settings tab and several windows. Texts in the header include and footer include windows are just added to the c++ code in the gcc tab so that you don' t have to write these #include and extern stuff every time. shellLog is a log window when the tool compiles your code, and make is the makefile to compile. These texts are editable except shellLog. There are some more settings. I'll summerize it lator.

Wednesday, June 4, 2008

Shake Command Window

Shake is a good script based application but somehow I couldn't find a script window. So I made it. It's just like Maya's script editor.















Upper text area is the history: every output to the shake console is redirected to this area, and below one is where you can write a shake script.
























I'm planning to add another feature with which you can write a Shake plug-in c++ source code and it is compiled with gcc, then loaded immediately (borrowing the idea from PyInline, scipy.weave, etc ;).
I don't know if I can make what I am thinking now due to Shake's restriction but it'll be fun if I can.

Thursday, May 29, 2008

Subclassing or parenting? (Shake)

When you reuse some class and make a new class in c++, you have two ways: making a subclass or having an instance of the class in your new class. The latter is considered to be the better one in general, unless there's conceptual "is-a" relationship.

I realized I also have the same two options when I am making a new Shake node from an existing one. Subclassing, or having an instance of the existing node as a child in my node. And this time I need to choose one of them in more practical way.

When I subclass a node, everything, UI, serialization, ... is o.k. but you need to make a creator function from the scratch, (see my previous post). I need to be careful not too miss anything, e.g. notify(), it's really time consuming because I need to observe the existing node closely.

When I use parenting, making a creator function will be probably easier if the number of arguments are fixed, but I need to connect plugs, need to implement some to have on screen control work as well with the new node, etc. And I see no way of calling a creator function inside my creator function if it accepts variable number of arguments. Maybe C language limitation? Now I'm stuck here...

I wish I had Shake source code, then subclassing would be really easy.


Jun 11,
After all I concluded I could do neither subclassing nor parenting. For a simple node like Move2D, I can guess exactly what the creator function does, and I can recreate it. But what I tried to use was much more complicated node (namely MultiPlane). I can observe its behavior closely and imitate the standard behavior, but how can I be sure that my creator function does exactly the same as what the standard one does? So I cannot make subclassing. Then my option left is parenting, but I cannot use it as well because parenting means I create MultiPlane object somewhere inside the creator function for my custom node. MultiPlane creator function has variable number of arguments so my creator function also needs variable number of arguments to pass them to the internal MultiPlane's creator function. How can I do that? 's printf() has a sibling vfprintf() that takes va_list but Multiplane creator function doesn't. It's not a good idea to use assembler here. Actually I came up with another idea. First I can make a standard multiplane and customize inside node structure after. But MultiPlane is MultiPlane and when it's saved and loaded, MultiPlane's creator function gets called. There's no place to hold additional parameters, sigh.

Wednesday, May 28, 2008

A tool to analyze Shake tree evaluation

I made a dummy node to log notify and eval plugs.
Every time notify() or eval() is called, plug's full name and new value is logged on the console.
When you connect a node like this,














Something like this is displayed on the Shake console.
It should be useful to analyze a tree.
























#include <nriiplug.h>
#include <nrifx.h>

class NRiFx_Linkage logNode : public NRiMonadic {
public:
logNode();
virtual ~logNode(){}
virtual int eval(NRiPlug *p);
virtual int notify(NRiPlug *p);
NRiDeclareNodeName(logNode);
protected:
void passData_(NRiPlug *from, NRiPlug* to);
void log_(NRiPlug* p, NRiName msg);
};

const NRiName logNode::thisClassName = "logNode";

logNode::logNode() : NRiMonadic()
{
in->setNotify(1, 1);
out->setNotify(1, 1);

in->time()->addDependency(out->time());
in->enable()->addDependency(out->enable());
in->roi()->addDependency(out->roi());
in->mask()->addDependency(out->mask());
in->iBuf()->addDependency(out->iBuf());
in->cacheLevel()->addDependency(out->cacheLevel());

out->width()->addDependency(in->width());
out->height()->addDependency(in->height());
out->bytes()->addDependency(in->bytes());
out->active()->addDependency(in->active());
out->oBuf()->addDependency(in->oBuf());
out->dod()->addDependency(in->dod());
out->bPixel()->addDependency(in->bPixel());
out->cacheId()->addDependency(in->cacheId());
out->bData()->addDependency(in->bData());
out->timeRange()->addDependency(in->timeRange());
}

int logNode::eval(NRiPlug *p)
{
NRiPlug* parent = p->getParent();
NRiPlug* otherParent = (parent == in)? out : in;
NRiPlug* otherPlug = otherParent->getChild(p->getName());
passData_(otherPlug, p);
log_(p, "eval");
return NRiMonadic::eval(p);
}

int logNode::notify(NRiPlug *p)
{
log_(p, "ntfy");
return NRiMonadic::notify(p);
}

void logNode::log_(NRiPlug* p, NRiName msg)
{
NRiName buf;
NRiSys::error((msg + ": " + p->getFullPathName() + " value=").getString());
switch(p->getType())
{
case kString:
NRiSys::error(p->asString().getString());
break;
case kInt:
NRiSys::error(NRiName(p->asInt()).getString());
break;
case kFloat:
NRiSys::error(NRiName(p->asFloat()).getString());
break;
case kDouble:
NRiSys::error(NRiName(p->asDouble()).getString());
break;
case kPtr:
buf.sprintf("0x%x", p->asPtr());
NRiSys::error(buf.getString());
break;
default:
break;
}
NRiSys::error("\n");
}

void logNode::passData_(NRiPlug *from, NRiPlug* to)
{

switch(from->getType())
{
case kString:
to->set(from->asString());
break;
case kInt:
to->set(from->asInt());
break;
case kFloat:
to->set(from->asFloat());
break;
case kDouble:
to->set(from->asDouble());
break;
case kPtr:
to->set(from->asPtr());
break;
default:
break;
}
}

extern "C"
{
NRiExport NRiIPlug *LogNode_(NRiIPlug *img)
{
logNode* fx = new logNode;
fx->in->connect(img);
fx->setParent(NRiNode::getRoot());
return fx->out;
}
}

Thursday, May 22, 2008

Creating a custom shake node deriving from an existing one

I just found you can make a custom shake node easily deriving from an existing shake node.


#include <NRiIPlug.h>
#include <NRiMove2D.h>

class NRiFx_Linkage TmpTest : public NRiMove2D {
public:
virtual int eval(NRiPlug *p)
{
NRiSys::error("TmpTest eval() called.\n"); //Just prints out something in the console.
return NRiMove2D::eval(p);
}
virtual ~TmpTest(){}
NRiDeclareNodeName(TmpTest);
};

const NRiName TmpTest::thisClassName = "TmpTest";

You may also want to use Move2D's creator function but you can't because a creator function usually creates a node and set default parameters at the same time. Instead you'll need to set parameter values directly.

extern "C"
{
NRiExport NRiIPlug *TmpTest_(
NRiIPlug *img,
const char *xPan,
const char *yPan,
const char *angle,
const char *aspectRatio,
const char *xScale,
const char *yScale,
const char *xShear,
const char *yShear,
const char *xCenter,
const char *yCenter,
const char *xFilter,
const char *yFilter,
const char *transformOrder,
const char *invertTransform,
const char *motionBlur,
const char *shutterTiming,
const char *shutterOffset,
const char *useReference,
const char *referenceFrame)
{
TmpTest * fx = new TmpTest;
fx->setParent(NRiNode::getRoot());
fx->in->connect(img);
fx->pXPan()->set(xPan);
fx->pYPan()->set(yPan);
fx->pAngle()->set(angle);
fx->pAspect()->set(aspectRatio);
fx->pXScale()->set(xScale);
fx->pYScale()->set(yScale);
fx->pXShear()->set(xShear);
fx->pYShear()->set(yShear);
fx->pXCenter()->set(xCenter);
fx->pYCenter()->set(yCenter);
fx->pXFilter()->set(xFilter);
fx->pYFilter()->set(yFilter);
fx->pTOrder()->set(transformOrder);
fx->pTReverse()->set(invertTransform);
fx->pMotionBlur()->set(motionBlur);
fx->pShutterTiming()->set(shutterTiming);
fx->pShutterOffset()->set(shutterOffset);
fx->pUseReference()->set(useReference);
fx->pReferenceFrame()->set(referenceFrame);
return fx->out;
}
}

And register it to the shake compiler (Part of the string to be passed to the cmplr).

"extern image TmpTest_(image,\n"
" float xPan = 0 , float yPan = 0,\n"
" float angle = 0, float aspectRatio = GetDefaultAspect(),\n"
" float xScale = 1, float yScale = xScale,\n"
" float xShear = 0, float yShear = 0,\n"
" float xCenter = width/2, float yCenter = height/2,\n"
" const char *xFilter = \"default\", const char *yFilter = xFilter,\n"
" const char *transformOrder = \"trsx\",\n"
" int invertTransform = 0,\n"
" float motionBlur = 0, float shutterTiming = 0.5, float shutterOffset = 0,\n"
" int useReference = 0, float referenceFrame = time\n"
" );\n"

Shake uses C++ in a straightforward way which brings this flexibility.
I'm quite impressed. Cool, cool

Saturday, April 26, 2008

Shake SDK

Bought it !















I'll watch it next week after I've done my current work, and write a review here.
Can't wait...