#ifndef ROTOR_NODES_DRAWING #define ROTOR_NODES_DRAWING #include "rotor.h" #include namespace Rotor { class Draw_node: public Image_node { public: Draw_node(){ create_image_input("image input","Image input"); //no title or description as it isn't intended for the user }; Draw_node(map &settings):Draw_node() { }; ~Draw_node(){}; Draw_node* clone(map &_settings) { return new Draw_node(_settings);}; virtual void vector_output(cairo_t * cr,const Frame_spec &frame){}; Image *output(const Frame_spec &frame){ Image *in=image_inputs[0]->get(frame); if (in){ image=(*in); } else image.clear(); //convert to 32 bit - this can probably be optimised further cv::Mat chans; cv::cvtColor(image.rgb, chans, CV_BGR2RGBA, 4); cairo_surface_t * cs = cairo_image_surface_create_for_data (chans.data, CAIRO_FORMAT_RGB24, image.w, image.h, image.w*4); cairo_t * cr = cairo_create (cs); //do any kind of vector drawing vector_output(cr,frame); //convert frame back to 24 bits cv::cvtColor(chans,image.rgb,CV_RGBA2BGR,3); cairo_destroy(cr); cairo_surface_destroy(cs); return ℑ } protected: Colour colour; private: }; class Text: public Draw_node { public: Text(){ title="Text"; description="Draws text"; create_attribute("text","Text to draw","Text","hello, world!"); create_attribute("colour","Colour to fill","Colour","FFFFFF"); create_parameter("number","number","Number to draw","Number",-99999999.0f); UID="7da93b94-2d0b-11e3-8940-77bce0f9d3e8"; }; Text(map &settings):Text() { base_settings(settings); }; ~Text(){}; Text* clone(map &_settings) { return new Text(_settings);}; void vector_output(cairo_t * cr,const Frame_spec &frame){ colour=Colour(attributes["colour"]->value); string text; if (parameters["number"]->value>-99999998.0f){ text=toString(parameters["number"]->value,4); } else text=attributes["text"]->value; cairo_text_extents_t te; cairo_set_source_rgb(cr, colour.Rfloat(),colour.Gfloat(),colour.Bfloat()); cairo_select_font_face (cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 120); cairo_text_extents(cr, text.c_str(), &te); cairo_move_to (cr,(frame.w-te.width)/2,frame.h*0.6); cairo_show_text (cr, text.c_str()); cairo_fill(cr); } private: }; #define SHAPE_circle 1 #define SHAPE_square 2 #define SHAPE_triangle 3 class Shape: public Draw_node { public: Shape(){ title="Shape"; description="Draws filled shapes"; create_parameter("x","number","X coordinate","X",0.0f); create_parameter("y","number","Y coordinate","Y",0.0f); create_parameter("scale","number","Scale","Scale",1.0f); create_parameter("rotation","number","Rotation","Rotation",0.0f); create_attribute("shape","Shape to draw","Shape","square",{"circle","square","triangle"}); create_attribute("colour","Colour to fill","Colour","FFFFFF"); UID="88c30140-2d0b-11e3-8db2-679d596166c1"; }; Shape(map &settings):Shape() { base_settings(settings); }; ~Shape(){}; Shape* clone(map &_settings) { return new Shape(_settings);}; void vector_output(cairo_t * cr,const Frame_spec &frame){ colour=Colour(attributes["colour"]->value); cairo_set_source_rgb(cr, colour.Rfloat(),colour.Gfloat(),colour.Bfloat()); cairo_save(cr); //not really even necessary? cairo_translate(cr, frame.w/2, frame.h/2); cairo_translate(cr, parameters["x"]->value * frame.w, parameters["y"]->value * frame.h); cairo_scale(cr, parameters["scale"]->value , parameters["scale"]->value ); cairo_rotate(cr,(parameters["rotation"]->value/180.0f)*M_PI); switch(attributes["shape"]->intVal) { case SHAPE_square: cairo_rectangle(cr,-frame.w/2,-frame.w/2,frame.w,frame.w); break; case SHAPE_circle: cairo_arc(cr,0,0,frame.w/2,0.0, 2 * M_PI); break; case SHAPE_triangle: //subtracting PI/2 =(1.5*PI)/3 so the triangle is pointing up cairo_line_to(cr,0,-frame.w/2); cairo_line_to(cr,cos((0.5 * M_PI)/3)*frame.w/2,sin((0.5 * M_PI)/3)*frame.w/2); cairo_line_to(cr,cos((2.5 * M_PI)/3)*frame.w/2,sin((2.5 * M_PI)/3)*frame.w/2); cairo_close_path(cr); break; } cairo_restore (cr); //not really even necessary? cairo_fill(cr); } private: }; class Audio_viz: public Draw_node { public: Audio_viz(){} Audio_viz(map &settings):Audio_viz() { base_settings(settings); }; ~Audio_viz(){}; Audio_viz* clone(map &_settings) { return new Audio_viz(_settings);}; void vector_output(cairo_t * cr,const Frame_spec &frame){ if (audioactive){ if (!frame.audio){ cerr<<"Audio_viz: audio not found"< &settings):Waves() { base_settings(settings); }; ~Waves(){}; Waves* clone(map &_settings) { return new Waves(_settings);}; void vector_audio_output(cairo_t * cr,const Frame_spec &frame){ stroke=Colour(attributes["stroke"]->value); fill=Colour(attributes["fill"]->value); int channel=attributes["channel"]->intVal-1; if (attributes["mode"]->value=="fill"||attributes["mode"]->value=="both") { cairo_set_source_rgba(cr, fill.Rfloat(),fill.Gfloat(),fill.Bfloat(),parameters["alpha"]->value); cairo_save(cr); cairo_translate(cr, 0, frame.h/2); cairo_scale(cr,1.0f,parameters["scale"]->value); cairo_line_to(cr, 0, 0); for (int i=0;isamples[i*frame.audio->channels]+channel)*frame.h)>>16); } cairo_line_to(cr, frame.w, 0); cairo_close_path(cr); cairo_restore (cr); cairo_fill(cr); } if (attributes["mode"]->value=="line"||attributes["mode"]->value=="both") { cairo_set_source_rgba(cr, stroke.Rfloat(),stroke.Gfloat(),stroke.Bfloat(),parameters["alpha"]->value); cairo_save(cr); cairo_translate(cr, 0, frame.h/2); cairo_scale(cr,1.0f,parameters["scale"]->value); cairo_set_line_width (cr, parameters["width"]->value); cairo_line_to(cr, 0, 0); for (int i=0;isamples[i*frame.audio->channels+channel])*frame.h)>>16); } cairo_line_to(cr, frame.w, 0); cairo_restore (cr); cairo_stroke(cr); } } private: Colour stroke; Colour fill; }; class Svg: public Draw_node { public: //rsvg should be cleanup? Svg(){ title="SVG"; description="Draws svg files"; create_parameter("x","number","X coordinate","X",0.0f); create_parameter("y","number","Y coordinate","Y",0.0f); create_parameter("scale","number","Scale","Scale",1.0f); create_parameter("rotation","number","Rotation","Rotation",0.0f); create_attribute("filename","SVG file to draw","Filename",""); UID="88c30140-2d0b-11e3-8db2-679d596166c1"; rsvg=nullptr; //g_type_init(); //does this have to be done only once? }; Svg(map &settings):Svg() { base_settings(settings); rsvg=rsvg_handle_new_from_file((settings["media_path"]+attributes["filename"]->value).c_str(),nullptr); if (rsvg) { rsvg_handle_get_dimensions(rsvg,&dims); cerr<<"Rotor: SVG loaded "<value<<" , "<value< &_settings) { return new Svg(_settings);}; void vector_output(cairo_t * cr,const Frame_spec &frame){ //to make it resolution independent //translate the difference between screen and drawing if (rsvg){ float scale=frame.w/dims.width; cairo_save(cr); //not really even necessary? cairo_translate(cr, frame.w/2, frame.h/2); cairo_translate(cr, parameters["x"]->value * frame.w, parameters["y"]->value * frame.h); cairo_scale(cr, parameters["scale"]->value*scale, parameters["scale"]->value*scale); cairo_rotate(cr,(parameters["rotation"]->value/180.0f)*M_PI); cairo_translate(cr, -frame.w/2, -frame.h/2); cairo_translate(cr, frame.w/2-(dims.width/2), frame.h/2-(dims.height/2)); rsvg_handle_render_cairo(rsvg,cr); cairo_restore (cr); //not really even necessary? cairo_fill(cr); } } private: RsvgHandle * rsvg; RsvgDimensionData dims; }; } #endif