summaryrefslogtreecommitdiff
path: root/rotord/src/nodes_maths.h
diff options
context:
space:
mode:
authorTim Redfern <tim@herge.(none)>2013-08-02 12:52:09 +0100
committerTim Redfern <tim@herge.(none)>2013-08-02 12:52:09 +0100
commit88e00292f311c9fabbe74db924f18af8199966ab (patch)
treee2e17d286a74fd49ecf981a4fbc505d1662bb337 /rotord/src/nodes_maths.h
parent8022d45fedd72f69a0c96ea4b651817321baddf8 (diff)
new arithmetic methods
Diffstat (limited to 'rotord/src/nodes_maths.h')
-rw-r--r--rotord/src/nodes_maths.h241
1 files changed, 240 insertions, 1 deletions
diff --git a/rotord/src/nodes_maths.h b/rotord/src/nodes_maths.h
index f8b6cd9..4b080d4 100644
--- a/rotord/src/nodes_maths.h
+++ b/rotord/src/nodes_maths.h
@@ -4,7 +4,246 @@
#include "rotor.h"
namespace Rotor {
-
+#define COMPARISON_Equal 1
+#define COMPARISON_Not_equal 2
+#define COMPARISON_Greater 3
+#define COMPARISON_Less 4
+#define COMPARISON_Greater_or_equal 5
+#define COMPARISON_Less_or_equal 6
+ class Comparison: public Signal_node {
+ public:
+ Comparison(){};
+ Comparison(map<string,string> &settings) {
+ base_settings(settings);
+ value=find_setting(settings,"value",0.0f);
+ string _op=find_setting(settings,"operator","==");
+ if (_op=="==") op=COMPARISON_Equal;
+ if (_op=="!=") op=COMPARISON_Not_equal;
+ if (_op==">") op=COMPARISON_Greater;
+ if (_op=="<") op=COMPARISON_Less;
+ if (_op==">=") op=COMPARISON_Greater_or_equal;
+ if (_op=="<=") op=COMPARISON_Less_or_equal;
+ }
+ void link_params() {
+ for (auto p:parameter_inputs){
+ if (p->parameter=="value") p->receiver=&value;
+ }
+ };
+ Comparison* clone(map<string,string> &_settings) { return new Comparison(_settings);};
+ const float output(const Time_spec &time) {
+ if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml
+ if (inputs[0]->connection) {
+ float in= (((Signal_node*)inputs[0]->connection)->get_output(time));
+ switch (op) {
+ case COMPARISON_Equal:
+ return fequal(value,in)?1.0f:0.0f;
+ break;
+ case COMPARISON_Not_equal:
+ return fequal(value,in)?0.0f:1.0f;
+ break;
+ case COMPARISON_Greater:
+ return fgreater(value,in)?1.0f:0.0f;
+ break;
+ case COMPARISON_Less:
+ return fless(value,in)?1.0f:0.0f;
+ break;
+ case COMPARISON_Greater_or_equal:
+ return fgreater_or_equal(value,in)?1.0f:0.0f;
+ break;
+ case COMPARISON_Less_or_equal:
+ return fless_or_equal(value,in)?1.0f:0.0f;
+ break;
+ }
+ }
+ }
+ return 0.0f;
+ }
+ int op;
+ float value;
+ };
+#define ARITHMETIC_plus 1
+#define ARITHMETIC_minus 2
+#define ARITHMETIC_multiply 3
+#define ARITHMETIC_divide 4
+#define ARITHMETIC_modulo 5
+#define ARITHMETIC_pow 6
+#define ARITHMETIC_sin 7
+#define ARITHMETIC_cos 8
+#define ARITHMETIC_ease 9
+ class Arithmetic: public Signal_node {
+ public:
+ Arithmetic(){};
+ Arithmetic(map<string,string> &settings) {
+ base_settings(settings);
+ value=find_setting(settings,"value",0.0f);
+ string _op=find_setting(settings,"operator","+");
+ if (_op=="+"||_op=="plus"||_op=="add") op=ARITHMETIC_plus;
+ if (_op=="-"||_op=="minus"||_op=="subtract") op=ARITHMETIC_minus;
+ if (_op=="*"||_op=="x"||_op=="multiply") op=ARITHMETIC_multiply;
+ if (_op=="/"||_op=="divide") op=ARITHMETIC_divide;
+ if (_op=="%"||_op=="mod"||_op=="modulo"||_op=="modulus") op=ARITHMETIC_modulo;
+ if (_op=="^"||_op=="power") op=ARITHMETIC_pow;
+ if (_op=="sin"||_op=="sine") op=ARITHMETIC_sin;
+ if (_op=="cos"||_op=="cos") op=ARITHMETIC_cos;
+ if (_op=="ease") op=ARITHMETIC_ease;
+ }
+ void link_params() {
+ for (auto p:parameter_inputs){
+ p->receiver=nullptr;
+ if (p->parameter=="value") p->receiver=&value;
+ }
+ };
+ Arithmetic* clone(map<string,string> &_settings) { return new Arithmetic(_settings);};
+ const float output(const Time_spec &time) {
+ if (op==ARITHMETIC_divide||op==ARITHMETIC_modulo){
+ if (value==0.0f) {
+ Logger& logger = Logger::get("Rotor");
+ logger.error("Arithmetic node: caught division by zero, frame "+time.frame());
+ return 0.0f;
+ }
+ }
+ if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml
+ if (inputs[0]->connection) {
+ float in= (((Signal_node*)inputs[0]->connection)->get_output(time));
+ switch (op) {
+ case ARITHMETIC_plus:
+ return in+value;
+ break;
+ case ARITHMETIC_minus:
+ return in-value;
+ break;
+ case ARITHMETIC_multiply:
+ return in*value;
+ break;
+ case ARITHMETIC_divide:
+ return in/value;
+ break;
+ case ARITHMETIC_modulo:
+ return fmod(in,value);
+ break;
+ case ARITHMETIC_pow:
+ return pow(in,value);
+ break;
+ case ARITHMETIC_sin:
+ return sin(in);
+ break;
+ case ARITHMETIC_cos:
+ return cos(in);
+ break;
+ case ARITHMETIC_ease:
+ return sin(in*M_PI);
+ break;
+ }
+ }
+ }
+ return 0.0f;
+ }
+ int op;
+ float value;
+ };
+ class Signal_divide: public Signal_node {
+ public:
+ Signal_divide(){};
+ Signal_divide(map<string,string> &settings) {
+ base_settings(settings);
+ divide_amount=ofToFloat(find_setting(settings,"amount"));
+ for (auto p:parameter_inputs){
+ if (p->parameter=="amount") p->receiver=&divide_amount;
+ }
+ };
+ Signal_divide* clone(map<string,string> &_settings) { return new Signal_divide(_settings);};
+ const float output(const Time_spec &time) {
+ if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml
+ if (inputs[0]->connection) {
+ return (((Signal_node*)inputs[0]->connection)->get_output(time))/divide_amount;
+ }
+ }
+ return 0.0f;
+ }
+ float divide_amount;
+ };
+ class Is_new_integer: public Signal_node {
+ public:
+ Is_new_integer(){};
+ Is_new_integer(map<string,string> &settings) {
+ base_settings(settings);
+ };
+ Is_new_integer* clone(map<string,string> &_settings) { return new Is_new_integer(_settings);};
+ const float output(const Time_spec &time) {
+ if (inputs[0]->connection) {
+ float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time));
+ float s2=(((Signal_node*)(inputs[0]->connection))->get_output(time.lastframe()));
+ if (((int)s1)>((int)s2)) {
+ return 1.0f;
+ }
+ }
+ return 0.0f;
+ }
+ };
+ class On_off: public Signal_node {
+ public:
+ On_off(){};
+ On_off(map<string,string> &settings) {
+ base_settings(settings);
+ };
+ On_off* clone(map<string,string> &_settings) { return new On_off(_settings);};
+ const float output(const Time_spec &time) {
+ if (inputs[0]->connection) {
+ float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time));
+ if ((int)s1%2) return 1.0f;
+ }
+ return 0.0f;
+ }
+ };
+ //pseudo random repeatable hash function
+ //http://create.stephan-brumme.com/fnv-hash/
+ const uint32_t Prime = 0x01000193; // 16777619
+ const uint32_t Seed = 0x811C9DC5; // 2166136261
+ /// hash a byte
+ inline uint32_t fnv1a(unsigned char oneByte, uint32_t hash = Seed)
+ {
+ return (oneByte ^ hash) * Prime;
+ }
+ /// hash a short (two bytes)
+ inline uint32_t fnv1a(unsigned short twoBytes, uint32_t hash = Seed)
+ {
+ const unsigned char* ptr = (const unsigned char*) &twoBytes;
+ hash = fnv1a(*ptr++, hash);
+ return fnv1a(*ptr , hash);
+ }
+ /// hash a 32 bit integer (four bytes)
+ inline uint32_t fnv1a(uint32_t fourBytes, uint32_t hash = Seed)
+ {
+ const unsigned char* ptr = (const unsigned char*) &fourBytes;
+ hash = fnv1a(*ptr++, hash);
+ hash = fnv1a(*ptr++, hash);
+ hash = fnv1a(*ptr++, hash);
+ return fnv1a(*ptr , hash);
+ }
+ class Random: public Signal_node {
+ public:
+ Random(){};
+ Random(map<string,string> &settings) {
+ base_settings(settings);
+ seed=(Seed+find_setting(settings,"seed",0));
+ cerr<<"random:: seed "<<seed<<" ("<<Seed<<")"<<endl;
+ };
+ Random* clone(map<string,string> &_settings) { return new Random(_settings);};
+ const float output(const Time_spec &time) {
+ if (inputs.size()) {
+ if (inputs[0]->connection) {
+
+ //hash the integer part and add the fractional part back on
+ float o=(((Signal_node*)inputs[0]->connection)->get_output(time));
+ uint32_t m=(int)o;
+ return ((float)(fnv1a(m,seed)%((uint32_t)time.duration)))+(o-m);
+ }
+ }
+ return 0.0f;
+ }
+ uint32_t seed;
+ private:
+ };
}
#endif \ No newline at end of file