Go Back   Cockos Incorporated Forums > REAPER Forums > REAPER for Video Editing/Mangling

Reply
 
Thread Tools Display Modes
Old 09-15-2022, 02:06 PM   #1
papagirafe
Human being with feelings
 
papagirafe's Avatar
 
Join Date: Aug 2020
Location: Brasil
Posts: 354
Default release: girafx:polygon (gfx_circle, gfx_triangle emulations) ***updated for 6.70

Hi folks!


gfx_polygon_demo.rpp

After a very interesting and challenging discussion in this thread:https://forum.cockos.com/showthread.php?t=270023, I am proud to annonce the release of a new preset that allows you to add colored shapes (beyond rectangles) to your videos, namely an emulation of gfx_circle() and gfx_triangle() available on JSFX side. It can also be used as a transparency mask.

Thew new functions are:
  • set_polycoords(coords="(x1,y1)(x2,y2)...(xn,yn)");
  • set_polycoords_translated(coords,xoff,yoff,rotatio n,ox,oy,aspect,zoom)
  • gfx_polygon()
  • gfx_polygon_regular(x,y,radius,sides,rotation,aspe ct)
  • gfx_circle(x,y,radius)
  • rel2abs() to convert relative offset to absolute pixel coordinates

You may add as many shapes as you want by adding a few simple lines of code in the "main code" section by replacing the demo lines. Note that that the preset will only work when a video source is present (input #0).It also uses pseudo-objects so you need to prefix each function call with a prefix unique for each new shape. For example:

gfx_set(10,20,30,1,0,-1,1);
mypoly.set_polycoords("(10,10)(1000,15)(500,1000)" ); //triangle
mypoly.gfx_polygon();
... or ...
//set coordinates but shift 10px up, rotate by $pi/7 on point (10,10), zoom 80%
mypoly.set_polycoords_translated("(10,10)(1000,15) (500,1000)",0,-10,$pi/7,10,10,1,0.8);
mypoly.gfx_polygon();

// regular 7 sides polygon centered at (500,500) with a radius of 200, no rotation
mypolyR.gfx_polygon_regular(500,500,200,7,0,1)

mycircle.gfx_circle(400,400,340);
The list of "@param" at the beginning is provided just to control the demo code. Feel free to replace it entirely to suit your needs. You may have noticed the "alpha 1" and "alpha 2":why? Alpha 1 (aka pixel alpha) affects the % of solid color that will mix into input #0; alpha 2 will affect the level of transparency of the shape when using "image overlay" basically creating a hole in your input #0 image to let show a source behind. The code also includes multiple performance optimisations (multi-threading and shape buffering) that will keep your CPU happy. On this, I recommend enabling video multi-threading (right click on video window->performance tweaks) to improve performance even further.

*** 2022-11-21: fix to support improved gfx_evalrect() in Repear v6.70 and new parameter "static bg" to enable/disable shape buffering that is only possible on static backgrounds
*** 2022-11-24: demo project updated as well


Code:
//girafx:polygons
//by papagirafe
//2022-11-21 v1.1 support for improved gfx_evalrect() in Rv6.70, new param "static bg"
//2022-09-15 v1.0

 // NB: param statements are just examples, none of the library functions depend on them
//@param xoff xoff 0 -1 1 0 0.01
//@param yoff yoff 0 -1 1 0 0.01
//@param zoom zoom 1 0.01 4 0 0.01
//@param rotation rotation 0 -180 180 0 0.1
rotation=rotation*$pi/180;  //convert to radian right now
//@param sides sides 5 3 20 11 1
//@param aspect aspect 0 -10 10 0 0.01
//@param cr red 1 0 1 0.5 .001
//@param cg green 1 0 1 0.5 .001
//@param cb blue 1 0 1 0.5 .001
//@param ca1 "alpha 1" 1 0 1 0.5 .001
//@param ca2 "alpha 2" 1 0 1 0.5 .001
//@param stabg "static bg" 0 0 1 0.5 1/

function round(v)(floor(v+.5));
//converts offsets (-1 to +1) to absolute pixel values
function rel2abs(x1*,y1*)(y1=(1+y1)*project_h/2;x1=(1+x1)*project_w/2);

//set drawing coordinates for gfx_polygon()
function set_polycoords(coords)
  instance(#coords,is_new_coords,evx,evy,evw,evh,blx,bly,blw,blh,ox,oy,evxBase,evyBase) //public 
  instance(_#ct1,#_ct2)  //private 
  local(minx,miny,maxx,maxy)
(
  //new coordinates? let's register the change
  strcmp(#coords,coords)?(
    #coords=coords; 
    is_new_coords=1;
    sprintf(#_ct1,"%s ",coords); #_ct2="";
    minx=project_w-1;miny=project_h-1;maxx=maxy=0;
    while(match("(%d,%d)%s",#_ct1,x1,y1,#_ct2))(
      #_ct1=#_ct2;
      minx=min(minx,x1); miny=min(miny,y1);
      maxx=max(maxx,x1); maxy=max(maxy,y1);
    );
    evx=evy=0;  //with temp bitmap, 0 is the reference
    blx=max(0,minx); bly=max(0,miny);
    blw=evw=min(project_w,maxx)-blx; blh=evh=min(project_h,maxy)-bly;
    evxBase=blx; evyBase=bly;
  );
);
// same as set_polycoords() but apply translation,rotation and zoom to base coordinates
function set_polycoords_translated(coords,xoff,yoff,rotation,ox,oy,aspect,zoom)
  instance(_#_ct1,#_ct2,#_ct3)  
  local(x1,y1,r,phi,yasp,xasp)
(
  yasp=aspect<0?abs(aspect)+1:1; xasp=aspect>0?aspect+1:1;
  sprintf(#_ct1,"%s ",coords); #_ct3=#_ct2="";
  while(match("(%d,%d)%s",#_ct1,x1,y1,#_ct2))(
    #_ct1=#_ct2;
    x1-=ox; y1-=oy;
    r=sqrt(x1^2+y1^2);
    phi=2*atan(y1/(x1+r))+rotation;
    x1=cos(phi)*r*zoom/xasp+xoff+ox; y1=sin(phi)*r*zoom/yasp+yoff+oy; 
    #_ct3+=sprintf(#,"(%d,%d)",x1,y1);
  );
  this.set_polycoords(#_ct3);
);

_refreshNeeded=stabg?0:1; //shape buffering possible on static images only
function _draw_optimized()
  global(_refreshNeeded,colorspace,gfx_r,gfx_g,gfx_b,gfx_a)
  instance(#init_code,#eval_code,blx,bly,blw,blh,_frameBuf,#_oldVals)
  local(r,g,b,a1,a2)
(
  colorspace='RGBA';
  r=gfx_r;g=gfx_g;b=gfx_b;a1=gfx_a;
  strcmp(#_oldVals,#eval_code)||_refreshNeeded?(
    _refreshNeeded=1;
    #_oldVals=#eval_code;
    _frameBuf==0?(
      gfx_set(0,0,0,1,0,-100,1);
      _frameBuf=gfx_img_alloc(blw,blh,1);
    ):(
      gfx_set(0,0,0,1,0,-100,1);
      gfx_img_resize(_frameBuf,blw,blh,1);
    );
    gfx_set(r,g,b,1,0,_frameBuf,0);
    gfx_blit(-1,0, 0,0,blw,blh, blx,bly,blw,blh);
    gfx_evalrect(0,0,blw,blh,#eval_code,0,-100,#init_code);
  );
  gfx_set(r,g,b,a1,0,-1,0);
  gfx_blit(_frameBuf,0, blx,bly,blw,blh);
);

function _init_get_triangle()(sprintf(#this._ct1,"%s ",#this.coords));
function _get_triangle()
  instance(x1,y1,x2,y2,x3,y3,#_ct1,#_ct2)
  local(xt,yt)
(
  match("(%d,%d)(%d,%d)(%d,%d)*",#_ct1,x1,y1,x2,y2,x3,y3)?(
    match("(%d,%d)%s",#_ct1,xt,yt,#_ct2)?((strcpy(#_ct1,#_ct2));1):0;
  ):0;
);
//arbitrary shape polygon
function gfx_polygon()
  global(_nt,colorspace,gfx_r,gfx_g,gfx_b,gfx_a,gfx_a2)
  local(trArea)
  instance(#init_code,#eval_code,evx,evy,evw,evh,evxBase,evyBase,blx,bly,blw,blh,x1,y1,x2,y2,x3,y3)
(
  // _nt: number of threads _1: x1 
  sprintf(#init_code,"_1=%d",evxBase);
  this._init_get_triangle();
  // _1: x1 _2:y1 _3:y1 base offset _slices:number of threads
  #eval_code=sprintf(#,"_3=_slice*%d/_slices+%d;\n0",evh,evyBase);
  while(this._get_triangle())( 
      trArea=abs((x1*(y2-y3) + x2*(y3-y1)+ x3*(y1-y2))/2.0);
      #eval_code+=sprintf(#,"||
((abs((_1*(%d-%d) + %d*(%d-(_2+_3))+ %d*((_2+_3)-%d))/2)+
abs((%d*((_2+_3)-%d) + _1*(%d-%d)+ %d*(%d-(_2+_3)))/2)+
abs((%d*(%d-(_2+_3)) + %d*((_2+_3)-%d)+ _1*(%d-%d))/2)) == %.1f)\n",
      y2,y3,x2,y3,x3,y2,
      x1,y3,y3,y1,x3,y1,
      x1,y2,x2,y1,y1,y2, trArea);
  );
  #eval_code+=sprintf(#,"?(r=%f*r+%d;g=%f*g+%d;b=%f*b+%d;a=%d);\n(_1+=1)>=%d?(_2+=1;_1=%d)",
      1-gfx_a,gfx_a*gfx_r*255,1-gfx_a,gfx_a*gfx_g*255,1-gfx_a,gfx_a*gfx_b*255,gfx_a2*255,evxBase+evw,evxBase);
  this._draw_optimized();
);

function gfx_polygon_regular(x,y,radius,sides,rotation,aspect)
  instance(#_ct1)
  local(i,xt,yt,ri,xasp,yasp)
(
  sides=round(sides);
  ri=sides==0?0:2*$pi/sides;
  //create multi-triangles coordinates
  yasp=aspect<0?abs(aspect)+1:1; xasp=aspect>0?aspect+1:1;
  i=0;#_ct1=""; loop(sides+1,
    xt=cos(i*ri+rotation)*radius/xasp+x; yt=sin(i*ri+rotation)*radius/yasp+y; 
    #_ct1+=sprintf(#,"(%d,%d)",xt,yt);
    (i&1)&&(sides>3)?#_ct1+=sprintf(#,"(%d,%d)",x,y);
    i+=1;
  );
  this.set_polycoords(#_ct1);
  this.gfx_polygon();
);

function gfx_circle(x,y,radius)
  global(_nt,colorspace,gfx_r,gfx_g,gfx_b,gfx_a,gfx_a2,gfx_dest,gfx_mode)
  instance(#init_code,#eval_code,evx,evy,evw,evh,evxBase,evyBase,blx,bly,blw,blh,_frameBuf)
(
  //init graphic engine with the 4 max coordinates
  this.set_polycoords(sprintf(#,"(%d,%d)(%d,%d)(%d,%d)(%d,%d)",
    round(cos(0)*radius+x),round(sin(0)*radius+y),
    round(cos($pi/2)*radius+x),round(sin($pi/2)*radius+y),
    round(cos($pi)*radius+x),round(sin($pi)*radius+y),
    round(cos(3*$pi/2)*radius+x),round(sin(3*$pi/2)*radius+y)));

  sprintf(#init_code,"_1=%d",evxBase);
  // _3:y1 base _1:x1  _2:y1
  #eval_code=sprintf(#,"
 _3=_slice*%d/_slices+%d;\n
 ((_1-%d)^2+((_2+_3)-%d)^2)<%d?(r=%f*r+%d;g=%f*g+%d;b=%f*b+%d;a=%d);
(_1+=1)>=%d?(_2+=1;_1=%d);
",
  evh,evyBase, x,y,radius^2,1-gfx_a,gfx_a*gfx_r*255,1-gfx_a,gfx_a*gfx_g*255,1-gfx_a,gfx_a*gfx_b*255,gfx_a2*255,
  evxBase+evw,evxBase);
  this._draw_optimized();
);

//****************************************************
// main code
input_info(0,project_w,project_h)?(
  gfx_blit(0);  //do no remove

 // *** demo code starts here
 // *** replace this section with your own code
  gfx_set(cr/2,cg/2,cb/2,1,0,-1,1);
  poly1.set_polycoords_translated("(960,0)(1900,500)(1700,100)(1080,900)",xoff*project_w/2,yoff*project_h/2,rotation,1538,308,aspect,zoom);
  poly1.gfx_polygon();
  
  gfx_set(cr,cg,cb,ca1,0,-1,ca2);
  x1=xoff-.4;y1=yoff;rel2abs(x1,y1);
  poly2.gfx_polygon_regular(x1,y1,project_h/2*zoom,sides,rotation,aspect);

  gfx_set(2*cr/3,2*cg/3,2*cb/3,ca1,0,-1,ca2);
  circ1.gfx_circle(project_w-zoom*200-50,project_h-zoom*200-50,zoom*200);
  // *** demo ends here
);
if you find this module helpful please consider a contribution, even small, to help support further cool developments! :-)

*** Donate to papagirafe ***
Attached Images
File Type: gif donation-ppg.gif (24.6 KB, 196 views)

Last edited by papagirafe; 11-24-2022 at 02:26 PM.
papagirafe is offline   Reply With Quote
Old 09-18-2022, 01:58 PM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 8,675
Default

Damn, the magic behind this code is hardcore !!


Too bad we can't just call a template code from within a VideoProcessor preset cause it is quite long and every video processor instance store all the code. But used sporadically in a project might be just fine !


I still advocate for native implementation but for now, this framework will for sure bring new possibilites ! Thanks very much for your time on this 👍
X-Raym is offline   Reply With Quote
Old 09-19-2022, 04:12 AM   #3
papagirafe
Human being with feelings
 
papagirafe's Avatar
 
Join Date: Aug 2020
Location: Brasil
Posts: 354
Default

Quote:
Originally Posted by X-Raym View Post
Damn, the magic behind this code is hardcore !!


Too bad we can't just call a template code from within a VideoProcessor preset cause it is quite long and every video processor instance store all the code. But used sporadically in a project might be just fine !


I still advocate for native implementation but for now, this framework will for sure bring new possibilites ! Thanks very much for your time on this 👍
Math + code that generate code + strings manipulation + evalrect() is indeed a recipe that Panoramix would apreciate! You ain't seen anything yet, more on this later...

I do miss an "import" or "include" statement like in scripts or JSFX. This preset is still short in my criterias and should not cause any problem even if used many times. With much larger presets (like my text overlay i published), the decoding process is fast and is done only once at the beginning of the track or item.

Glad to be of help et à bientôt!

p.s. I forgot to mention, if you change the "aspect" and rotate the shape it gives a nice pseudo 3d feel (actually isometric).
papagirafe is offline   Reply With Quote
Old 11-21-2022, 08:13 AM   #4
papagirafe
Human being with feelings
 
papagirafe's Avatar
 
Join Date: Aug 2020
Location: Brasil
Posts: 354
Default

2022-11-21 new version
papagirafe is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 10:43 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2022, vBulletin Solutions Inc.