Old 04-02-2022, 02:53 PM   #1
ashcat_lt
Human being with feelings
 
Join Date: Dec 2012
Posts: 7,296
Default Help with gfx_rotoblit?

This is killing me. Mostly because it's probably a lot simpler than I'm making it out to be, but I just can't get it to work.
Code:
 gfx_rotoblit(srcidx, angle, x, y, w, h, srcx, srcy, w, h, cliptosrcrect, centxoffs, centyoffs] )
I want to be able to take a rectangle the size of the project window, scale it down on both the x and y axis, put it somewhere on the screen, and rotate it by a certain amount. I have determined that in order to do that and have it actually work the way I want it, it has to start out (srcidx, angle, 0, 0, project_w, project_h, ...) but then I have to do some chain of inverse transorms to figure out srcx, srcy, and then that set of w, h... and I'm not sure the center offsets even help, but they sure don't seem to do what I want them to do.

I don't super need a lecture on linear algebra and all that matrix stuff. What I do kind of need is a function something like:
Code:
sane_rotoblit (sridx, dest_cntr_x, dest_center_y, scale_x, scale_y, angle)
If you can hook me up with such a thing, I'll gladly buy you a beer! (...or 12. Heck, if you drink Hamm's, I'll buy you 30!)
ashcat_lt is online now   Reply With Quote
Old 04-02-2022, 07:50 PM   #2
papagirafe
Human being with feelings
 
papagirafe's Avatar
 
Join Date: Aug 2020
Location: Brasil
Posts: 690
Default

I had at some point in the past understood how the rotoblit() function works but I was never able to prevent it from cutting the edges of a full image even with downsizing. The only trick I found is to rotoblit() in the middle of a temporary larger image and then blit() back to the frame buffer but you end up with some opaque black around the shape unless you allocate an temporary image with an alpha plane.
papagirafe is offline   Reply With Quote
Old 04-03-2022, 01:10 AM   #3
ashcat_lt
Human being with feelings
 
Join Date: Dec 2012
Posts: 7,296
Default

Well yeah see that’s what happens if you use it “as intended”. That is, it gets clipped to the destination w and h, which is why I want to leave those as the full window. It then will work for what I’m trying to do, if I can just figure out the right value for the other arguments to reliably place things.

BTW I did try your trick for allocating a transparent space, but couldn’t get it to work for some reason. Then I realized it wasn’t super necessary if only…

Last edited by ashcat_lt; 04-03-2022 at 01:16 AM.
ashcat_lt is online now   Reply With Quote
Old 04-03-2022, 04:03 AM   #4
papagirafe
Human being with feelings
 
papagirafe's Avatar
 
Join Date: Aug 2020
Location: Brasil
Posts: 690
Default

Quote:
Originally Posted by ashcat_lt View Post
Well yeah see that’s what happens if you use it “as intended”. That is, it gets clipped to the destination w and h, which is why I want to leave those as the full window. It then will work for what I’m trying to do, if I can just figure out the right value for the other arguments to reliably place things.

BTW I did try your trick for allocating a transparent space, but couldn’t get it to work for some reason. Then I realized it wasn’t super necessary if only…
Yes the transparent bitmap is only required when you reduce the size of the object but still the rotoblit() function will cut the bitmap. I have a strategy to avoid that but it involves using some esoteric forms of xfomblit(). In the mean time my item stretch preset does rotations...
papagirafe is offline   Reply With Quote
Old 04-03-2022, 10:32 AM   #5
papagirafe
Human being with feelings
 
papagirafe's Avatar
 
Join Date: Aug 2020
Location: Brasil
Posts: 690
Default

Quote:
Originally Posted by ashcat_lt View Post
Well yeah see that’s what happens if you use it “as intended”. That is, it gets clipped to the destination w and h, which is why I want to leave those as the full window. It then will work for what I’m trying to do, if I can just figure out the right value for the other arguments to reliably place things.

BTW I did try your trick for allocating a transparent space, but couldn’t get it to work for some reason. Then I realized it wasn’t super necessary if only…
You're in luck! I found an non-clipping image overlay preset using "rotoblit()" that I made in my "lab projects" folder. Hope this helps.
Code:
//Overlay: image w/non-clipping rotation
//by papagirafe
//@param1:zoom 'zoom %' 100 1 400 100 0.1
//@param2:rot 'rotation (deg)' 0 -180 180 0 0.1
//@param4:posx 'offset x' 0 -2 2 0 0.001
//@param5:posy 'offset y' 0 -2 2 0 0.001
//@param6:centx 'axis offset x' 0 -2 2 0 0.001
//@param7:centy 'axis offset y' 0 -2 2 0 0.001
//@param9:debug 'monitor' 0 0 1 0.5 1

function radius_max()
(
    zsw=floor(sw*zoom+0.5);
    zsh=floor(sh*zoom+0.5);
    zax=floor((centx+sw/2)*zoom+0.5);
    zay=floor((centy+sh/2)*zoom+0.5);
    a2tl=ceil(sqrt(abs(0-zax)^2 + abs(0-zay)^2));
    a2tr=ceil(sqrt(abs(zsw-zax)^2 + abs(0-zay)^2));
    a2bl=ceil(sqrt(abs(0-zax)^2 + abs(zsh-zay)^2));
    a2br=ceil(sqrt(abs(zsw-zax)^2 + abs(zsh-zay)^2));
    max(max(a2tl,a2tr),max(a2bl,a2br));
);

function monitor()
(
  sprintf(t=#,"source:%5dx%-5d\nzoomed:%5dx%-5d\n  axis:%5i,%-5i\nradius max:%-6d ",
          sw,sh,
          floor(sw*zoom+0.5),floor(sh*zoom+0.5),
          (centx+sw/2)*zoom,(centy*zoom+sh/2)*zoom,
          radius_max();
          );
  gfx_setfont(0.05*project_h,"lucida console",'V');
  gfx_set(1,1,1,1);
  gfx_str_draw(t);
);

zoom/=100;
rotation=rot/180*$pi;
input_info(0,sw,sh);
pw=project_w; ph=project_h;
centx*=sw/2; centy*=sh/2;
posx*=pw/2; posy*=ph/2;
rmax = radius_max();

gfx_blit(1,1);

gfx_rotoblit( 0,rotation,
              posx-pw*zoom+pw/2-sw*zoom/2,posy-ph*zoom+ph/2-sh*zoom/2,pw*3*zoom,ph*3*zoom,
              -sw,-sh,sw*3,sh*3,
              1,
              centx,centy
              );



debug ? monitor();

Last edited by papagirafe; 04-03-2022 at 01:55 PM. Reason: found better code
papagirafe is offline   Reply With Quote
Old 04-05-2022, 12:56 PM   #6
ashcat_lt
Human being with feelings
 
Join Date: Dec 2012
Posts: 7,296
Default

I really do appreciate you're trying to help, but honestly, you didn't give me specifically what i asked for. I'll buy you a drink next time you're in town anyway.

I think I made the whole thing a lot more complicated than I really needed to, and this first demonstration thing doesn't ultimately accomplish much different from what the built in track opacity/zoom/an does. But, I found my way through it, and now have a function with which I can interact in a way that makes sense to me. ATM it depends on a few other functions from a library I'm developing, but I intend to roll it down into a standalone thing at some point.

Code:
graf_rotoblit (src, x, y, w, h, angle)
  src - input track or other allocated image index
  x, y - in "cartesian coordinates" with (0,0) in the center and (1,1) in the upper left, just like we're used to seeing in algebra class.
  w, h - width and height of the result as a fraction of the window size.  
  angle - in radians.
It needs to be called on a namespace which includes a w and h parameter. In this example, I use window.w and window.h. It is designed to allow the destination to be whatever, and I think it can end up being nested and stuff.

Code:
//demonstration of graf_rotoblit with supporting functions

//@param1:ox 'x' -1 -1 1 0 0.1
//@param2:oy 'y' 1 -1 1 0 0.1
//@param3:x_size 'width' 1
//@param4:y_size 'height' 1
//@param5:angle 'angle' 0
//@param6:back 'background: black/input' 0 0 1 0.5 1
//@param7:src 'source track' 0 0 50 25 1

math.huge = 2^32 - 1;
math.two_pi = $pi * 2;
math.clamp_huge.min = -math.huge;  math.clamp_huge.max = math.huge;

function clamp(in)
  (max(this.min, min(this.max, in));
  );

function lerp (o_min, o_max, t_min, t_max, o_val)
  local (out, o_dif)
  (o_dif = o_max - o_min;
   o_dif == 0 ?
   out = 0:
   out = t_min + ((o_val - o_min) / (o_dif)) * (t_max - t_min));

function vector (o_x, o_y, t_x, t_y)
  (this.origin.x = o_x;
   this.origin.y = o_y;
   this.term.x = t_x;
   this.term.y = t_y;
   this.dif.x = t_x - o_x;
   this.dif.y = t_y - o_y;
   this.cntr.x = 0.5 * (this.origin.x + this.term.x);
   this.cntr.y = 0.5 * (this.origin.y + this.term.y);
   this.dif_2.x = this.dif.x * this.dif.x;
   this.dif_2.y = this.dif.y * this.dif.y;
   this.sqr_d = this.dif_2.x + this.dif_2.y;
   this.distance = sqrt (this.sqr_d);
   this.trig.sin_d = this.dif.y / this.distance;
   this.trig.cos_d = this.dif.x / this.distance;
   this.trig.tan_d = math.clamp_huge.clamp (this.dif.y / this.dif.x);
   this.norm.origin.x = 0;
   this.norm.origin.y = 0;
   this.norm.dif.x = this.norm.term.x = this.trig.cos_d;
   this.norm.dif.y = this.norm.term.y = this.trig.sin_d;);

function vector_rotate_angle (v1*, angle)
  local (sin_b, cos_b, sin_ab, cos_ab)
  (sin_b = sin (angle);
   cos_b = cos (angle);
   sin_ab = v1.distance * (v1.trig.sin_d * cos_b + sin_b * v1.trig.cos_d);
   cos_ab = v1.distance * (cos_b * v1.trig.cos_d - sin_b * v1.trig.sin_d);
   this.vector (v1.origin.x, v1.origin.y, v1.origin.x + cos_ab, v1.origin.y + sin_ab););

function graf_translate_point (p1*)
  (this.x = lerp (-universe.scale, universe.scale, window.origin.x, window.term.x, p1.x);
   this.y = lerp (-universe.scale, universe.scale, window.term.y, window.origin.y, p1.y););

function graf_rotoblit (src, x, y, w, h, angle)
local (half_x, half_y, srcw, srch, cx, cy, scrx, srcy)
instance (source, target)
  (scale_x = 1/w;
   scale_y = 1/h;
   half_x = 0.5 * scale_x;
   half_y = 0.5 * scale_y;
   srcw = this.w * scale_x;
   srch = this.h * scale_y;
   cx = -srcw * 0.5;
   cy = -srch * 0.5;

   target.vector (0, 0, x, y);
   target.vector_rotate_angle(target, angle);
   source.x = scale_x * target.dif.x - (1 - scale_x);
   source.y = scale_y * target.dif.y + (1 - scale_y);
   source.graf_translate_point (source);
   srcx = -source.x;
   srcy = -source.y;
   gfx_rotoblit (src, angle, 0, 0, this.w, this.h, srcx, srcy, srcw, srch, 0);
  );



universe.scale = 1;
window.vector (0, 0, project_w, project_h);
window.w = window.dif.x;
window.h = window.dif.y;
gfx_set (0);
gfx_fillrect (window.origin.x, window.origin.y, window.w, window.h);
back == 1 ? gfx_blit (0);

angle = math.two_pi * angle;
window.w = window.dif.x;
window.h = window.dif.y;
window.graf_rotoblit (src, ox, oy, x_size, y_size, angle);
This really is leading somewhere...

Gonna go buy myself a beer or 12.
ashcat_lt is online now   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 04:36 PM.


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