View Full Version : A question about NodeHandler's Evaluation function
jrandom
04-16-2011, 12:08 PM
I've finally made it to the Evaluation function of my very first node plug-in and have a code structure question:
Evaluate() is handed the NodeOutputID of the output to evaluate. This translates to a void* which sadly does not work in switch() statements. I'd like to avoid a messy chain of if/else statements and if I were strictly in 32-bit land I'd just cast the void* to an int and be done with it. I'm much hazier in 64-bits if it is safe to cast void* to int (or unsigned as the case may be) as was wondering how you other node developers tackled this particular issue.
Sidenote: I haven't coded in straight C for some time since my job has me neck-deep in C#. Once I get this node working I might refactor it into a C++ object with a C interface, but I've got to get it up and running first! :)
Lightwolf
04-16-2011, 12:31 PM
You can't use switch because neither the void * you get nor the IDs of your own outputs (which is the adress of your node output) are constant.
if {} if {} else {} it is.
Cheers,
Mike
P.S. You might want to look at our open source C++ wrapper for the LW SDK: http://lwpp.db-w.com - one of the (few) samples is a node as well: http://lwpp.db-w.com/advanced__plugin.html
jrandom
04-16-2011, 12:40 PM
You can't use switch because neither the void * you get nor the IDs of your own outputs (which is the adress of your node output) are constant.
To make sure I've got this right: I compare Evaluate()'s node ID to the NodeOutputID I get from Output_Functions->create(), correct?
if {} if {} else {} it is.
Argh! Argh, I say!
P.S. You might want to look at our open source C++ wrapper for the LW SDK: http://lwpp.db-w.com - one of the (few) samples is a node as well: http://lwpp.db-w.com/advanced__plugin.html
Nice! I'll definitely dig through that for inspiration. (I have my own particular way of structuring objects so I'll be writing my own wrapper from scratch, but I'll use good ideas no matter where they come from.)
Lightwolf
04-16-2011, 02:24 PM
To make sure I've got this right: I compare Evaluate()'s node ID to the NodeOutputID I get from Output_Functions->create(), correct?
Precisely.
Nice! I'll definitely dig through that for inspiration. (I have my own particular way of structuring objects so I'll be writing my own wrapper from scratch, but I'll use good ideas no matter where they come from.)
That's a shame... wrapping the whole SDK is a daunting tasks and I could use some help for the parts that haven't been wrapped yet (of which there's still quite a few).
Cheers,
Mike
jrandom
04-16-2011, 03:01 PM
That's a shame... wrapping the whole SDK is a daunting tasks and I could use some help for the parts that haven't been wrapped yet (of which there's still quite a few).
If our C++ approaches were similar I'd be grabbing your wrapper this instant. :)
I tend to favor composition over inheritance and my inheritance hierarchy approach definitely differs from yours. For example, you have an XPanel Node that new nodes inherit from, whereas I would have an XPanel object/wrapper as a member of the node class itself. My brain sees your design as "upside down" and has been a real detriment for me attempting to use a lot of C++ code written by other people.
I also tend to be pretty verbose when it comes to variable and object names and I'm very picky about capitalization, underscores, and code formatting (a habit developed as self-defense from working on worst-case-scenario C++ code from jobs I've had in the past).
(I'm attaching my work-in-progress C code as an example. I consider it to be clean-ish looking but sloppily organized. I'll be happier when I understand node-writing better and can re-work it into a C++ object.)
I'm not saying your code is bad, not by any stretch of the imagination, it's merely different. I've found that working with code that deviates from my particular design style causes me a lot of frustration and is probably the biggest indicator that I'm a mediocre coder at best. I have to write code that I know for sure I can come back to in six months and not rip my hair out deciphering what the heck I was doing when I wrote it. :)
That being said, I always try to learn from others and I incorporate ideas that "click" with me into my code design. My guiding principle is that code should be immediately obvious at a glance as to what it's doing and why it's doing what it's doing. This is usually not an achievable goal, but it helps me keep my code cleaner than it would be otherwise.
Once I get something I'm happy with, I'll be distributing the source along with the compiled node(s) in the hopes that maybe it will help other fledgling node coders out, even if just a little.
Hey, since you seem very well-versed in node writing, I have another question: If I have an output that connects to two other inputs then that output get evaluated twice, right? It would be really nice if my node could re-use a previously-evaluated value -- what information would I have to look at to determine if an evaluation request was coming from the same node network eval pass so that a value could be re-used?
Lightwolf
04-16-2011, 04:09 PM
I tend to favor composition over inheritance and my inheritance hierarchy approach definitely differs from yours. For example, you have an XPanel Node that new nodes inherit from, whereas I would have an XPanel object/wrapper as a member of the node class itself. My brain sees your design as "upside down" and has been a real detriment for me attempting to use a lot of C++ code written by other people.
To be frank the initial design is quite old and comes from a time when I was relatively new to C++. Nowadays I'd probably still keep the basic structure the same though but would probably use templates a lot more.
It certainly shows in some of the naming conventions that are jumbled together in the code.
One reason for the inheritance is dealing with plugin types that can either be based on XPanels or LWPanels. It also makes overriding the callbacks a lot easier especially once you need to deal with member variables as well.
I do tend to work a lot with other SDKs or APIs though - so switching to something else is a matter of habit by now.
In the end though, the design goal for lwpp was to make things easier, quicker and safer. And that seems to have worked out well (even though there's still plenty to improve one).
I'm not saying your code is bad, not by any stretch of the imagination, it's merely different. I've found that working with code that deviates from my particular design style causes me a lot of frustration and is probably the biggest indicator that I'm a mediocre coder at best. I have to write code that I know for sure I can come back to in six months and not rip my hair out deciphering what the heck I was doing when I wrote it. :)
Oh, no worries, I know what you mean. Luckily I seem to be able to re-visit my older stuff and still understand it.
I certainly rip my hair out at the quality of the old code - but that's a different topic ;)
Hey, since you seem very well-versed in node writing, I have another question: If I have an output that connects to two other inputs then that output get evaluated twice, right? It would be really nice if my node could re-use a previously-evaluated value -- what information would I have to look at to determine if an evaluation request was coming from the same node network eval pass so that a value could be re-used?
In a way you can't. First of all it'd need to be the same threads as well as the same recursion level... but then you also need to make sure that a it is a second evaluation and not the _next_ evaluation within that thread and recursion level.
The simplest solution is to pass it through the Cache node that's a part of the db&w Tools. It has been designed explicitly for that case ;)
Cheers,
Mike
jrandom
04-16-2011, 04:28 PM
The simplest solution is to pass it through the Cache node that's a part of the db&w Tools. It has been designed explicitly for that case ;)
I suppose it would be the acme of foolishness to ask you how that node works so I could use the technique in my own nodes. :rolleyes:
Lightwolf
04-16-2011, 05:25 PM
I suppose it would be the acme of foolishness to ask you how that node works so I could use the technique in my own nodes. :rolleyes:
Nope, not at all. Shoot me a mail and I'll send you the source (it does depend on lwpp though and probably to a small part on a custom library, but that's only to leverage TLS).
michael(dot)wolf(a)db-w(dot)com
Cheers,
Mike
jrandom
04-16-2011, 05:33 PM
Thank you! E-mail shall arrive shortly.
jrandom
04-16-2011, 09:00 PM
When an input is being evaluated, should I be using Input_Functions->check() to see if it is connected before calling Input_Functions->evaluate() or does evaluate() do that automatically? The documentation doesn't specify and the sample code doesn't make it clear (although I'm currently guessing that a call to check() is not necessary).
Lightwolf
04-17-2011, 07:07 AM
When an input is being evaluated, should I be using Input_Functions->check() to see if it is connected before calling Input_Functions->evaluate() or does evaluate() do that automatically? The documentation doesn't specify and the sample code doesn't make it clear (although I'm currently guessing that a call to check() is not necessary).
It does it automatically. check() is used to ghost controls when the respective input is connected.
Cheers,
Mike
vBulletin® v3.8.2, Copyright ©2000-2012, Jelsoft Enterprises Ltd.