summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xrotord/rotor.cpp3
-rwxr-xr-xrotord/rotor.h126
2 files changed, 118 insertions, 11 deletions
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp
index 37af5a1..887fc9f 100755
--- a/rotord/rotor.cpp
+++ b/rotord/rotor.cpp
@@ -18,12 +18,15 @@ Node_factory::Node_factory(){
add_type("video_cycler",new Video_cycler());
add_type("luma_levels",new Luma_levels());
add_type("echo_trails",new Echo_trails());
+ add_type("time",new Time());
add_type("track_time",new Track_time());
add_type("comparison",new Comparison()); //TODO: alias to symbols
add_type("arithmetic",new Arithmetic()); //TODO: alias to symbols
add_type("signal_colour",new Signal_colour());
add_type("signal_greyscale",new Signal_greyscale());
add_type("image_arithmetic",new Image_arithmetic());
+ add_type("random",new Random());
+ add_type("blend",new Blend());
}
bool Signal_input::connect(Signal_node* source) {
diff --git a/rotord/rotor.h b/rotord/rotor.h
index b681e72..0c16df7 100755
--- a/rotord/rotor.h
+++ b/rotord/rotor.h
@@ -4,6 +4,9 @@ nodes can have many inputs but only 1 output
image nodes that use an image as input can pass on the incoming image only if its unchanged.
TODO - parameter class that automatically links variable to correctly named inputs
+TODO - use try.. catch and dynamic_cast to verify node connections rather than checking 'type' tag
+
+TODO - put the boilerplate code for checking inputs into the base class, finally call checked_output
*/
#include <unordered_map>
@@ -111,6 +114,34 @@ namespace Rotor {
AVPacket packet;
};
+ class pixeltables{
+ //handy pixel arithmetic lookup tables as nested arrays
+ //so - pixels.add[0x78][0x66]; will give the precalculated result of adding with saturation
+ public:
+ pixeltables(){
+ add=new uint8_t*[0xFF];
+ multiply=new uint8_t*[0xFF];
+ for (int i=0;i<0xFF;i++){
+ add[i]=new uint8_t[0xFF];
+ multiply[i]=new uint8_t[0xFF];
+ for (int j=0;j<0xFF;j++){
+ add[i][j]=(uint8_t)min(i+j,0xFF);
+ multiply[i][j]=(uint8_t)((((float)i)/255.0f)*(((float)j)/255.0f)*255.0f);
+ }
+ }
+ }
+ virtual ~pixeltables(){
+ for (int i=0;i<0xFF;i++){
+ delete[] add[i];
+ delete[] multiply[i];
+ }
+ delete[] add;
+ delete[] multiply;
+ }
+ uint8_t **add;
+ uint8_t **multiply;
+ };
+ static pixeltables pixels;
class Time_spec{
public:
Time_spec(){};
@@ -221,8 +252,20 @@ namespace Rotor {
}
else {
for (int i=0;i<w*h*3;i++){
- //creates rainbow overload RGBdata[i]=(unsigned char)(((int)other.RGBdata[i]+(int)RGBdata[i])&0x00FF);
- RGBdata[i]=(unsigned char)min((int)other.RGBdata[i]+(int)RGBdata[i],0x00FF);
+ //calculate with tables
+ RGBdata[i]=pixels.add[RGBdata[i]][other.RGBdata[i]];
+ }
+ }
+ return *this;
+ }
+ Image & operator*=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot multiply images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ RGBdata[i]=pixels.multiply[RGBdata[i]][other.RGBdata[i]];
}
}
return *this;
@@ -424,6 +467,17 @@ namespace Rotor {
vampHost::Analyser analyser;
map <string,float> params;
};
+ class Time: public Signal_node {
+ public:
+ Time(){};
+ Time(map<string,string> &settings) {
+ base_settings(settings);
+ };
+ Time* clone(map<string,string> &_settings) { return new Time(_settings);};
+ const float output(const Time_spec &time) {
+ return time.time;
+ }
+ };
class Track_time: public Signal_node {
public:
Track_time(){};
@@ -629,27 +683,24 @@ namespace Rotor {
Random(){};
Random(map<string,string> &settings) {
base_settings(settings);
- seed=(float)find_setting(settings,"seed",Seed);
- for (auto p:parameter_inputs){
- if (p->parameter=="seed") p->receiver=&seed;
- }
- key=0xffffffff;
+ 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,(uint32_t)(seed+0.5f)))+(o-m);
+ return ((float)(fnv1a(m,seed)%((uint32_t)time.duration)))+(o-m);
}
}
return 0.0f;
}
- float seed;
+ uint32_t seed;
private:
-
};
class Signal_output: public Signal_node {
public:
@@ -706,7 +757,7 @@ namespace Rotor {
~Invert(){ delete image;};
Invert* clone(map<string,string> &_settings) { return new Invert(_settings);};
Image *output(const Frame_spec &frame){
- if (inputs.size()) {
+ if (image_inputs.size()) {
if (image_inputs[0]->connection){
if (inputs[0]->connection) {
if (fgreater_or_equal(1.0f,(((Signal_node*)inputs[0]->connection)->get_output((Time_spec)frame)))) {
@@ -1118,6 +1169,59 @@ namespace Rotor {
unordered_map<int,Image*> images;
float mode; //TODO make int, enum string parameter types
};
+ #define BLEND_screen 1
+ #define BLEND_multiply 2
+ #define BLEND_blend 3
+ class Blend: public Image_node {
+ public:
+ Blend(){};
+ Blend(map<string,string> &settings) {
+ base_settings(settings);
+ image=new Image();
+ amount=find_setting(settings,"amount",1.0f);
+ string _mode=find_setting(settings,"mode","screen");
+ if (_mode=="screen") mode=BLEND_screen;
+ if (_mode=="multiply") mode=BLEND_multiply;
+ if (_mode=="blend") mode=BLEND_blend;
+ };
+ void link_params() {
+ for (auto p:parameter_inputs){
+ if (p->parameter=="amount") p->receiver=&amount;
+ }
+ };
+ ~Blend(){ delete image;};
+ Blend* clone(map<string,string> &_settings) { return new Blend(_settings);};
+ Image *output(const Frame_spec &frame){
+ if (image_inputs.size()) {
+ if (image_inputs[0]->connection){
+ if (inputs.size()>1) {
+ if (image_inputs[1]->connection) {
+ //copy incoming image **writable
+ image->free();
+ image=(((Image_node*)image_inputs[0]->connection)->get_output(frame))->clone();
+ switch(mode){
+ case BLEND_screen:
+ (*image)+=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
+ break;
+ case BLEND_multiply:
+ (*image)*=(*(((Image_node*)image_inputs[1]->connection)->get_output(frame)));
+ break;
+
+ }
+ return image;
+ }
+ }
+ //if there aren't 2 image inputs connected just return the first
+ return (((Image_node*)image_inputs[0]->connection)->get_output(frame));
+ }
+ }
+ return nullptr;
+ }
+ private:
+ Image *image; //is an image generator
+ int mode;
+ float amount; //for blend
+ };
//-------------------------------------------------------------------
class Node_factory{
public: