Wingnut

The Wingnut Chronicles

Recommended Posts

Uh oh, I gotz a little bug that I can't fig.

https://www.babylonjs-playground.com/#PBVEM#189

If you watch console, executeWhenReady is running, all is fine.  I also report a little array called psTank, which is to be an array filled with 24 Babylon particleSystems.

Lines 1690-1694 is a little for-loop that tries to fill the psTank array... with BJS particle systems.

Activating line 1692... fills the tank.  (re-run - check psTank report at console... to see that it is filled with objects.)

BUT... when 1692 is activated, executeWhenReady() doesn't execute, and the playground "hangs" in "Loading assets...Please wait".

I've seen this before, but, I can't fig why this is happening.  HELP (please) (thx)!

Why in the heck... does filling the array... hang the PG app and refuse to run EWR?  Any ideas?   (Wingy scratches his beard and ponders, aimlessly)

Make 1692 be:   psTank.push(new Object());  ...it works fine... EWR executes.  Do arrays hate storing particleSystems?  :)  Maybe so, eh? 

(it's actually the CREATING of the 24 particleSystems that is causing the problem... and NOT the storing of them in an array.)

Aside:  There's lots of new particleSystem features in BJS 3.3.  Somebody has been busy, and helpful.  Cool.

Share this post


Link to post
Share on other sites

Ah, thx for the viewing, testing, and little PG, @JohnK

I think I figured-out my mistake (thx to your help).

https://www.babylonjs-playground.com/#0P0YXG#2

https://github.com/BabylonJS/Babylon.js/blob/master/src/Particles/babylon.particleSystem.ts#L1677  <== According to the "rules" for setting a particleSystem to isReady() => true... 

...the particle system must have an emitter and a "ready" particleTexture.

Well... in my original code, I have no emitters set on the 24 particleSystems.

I was planning to set the PS emitters (and direction 1/2 values)... during the actual thrust() function (later, when button-press happens). 

I was hoping to eventually/possibly reduce the amount of particleSystems... to 8 (possible 4 rot thrust-ports and 4 trans thrust-ports... active at same time).  (Example: barrel-rolling while forward thrusting.) 

I think... using a customStartPosition() func, I could use a single particleSystem to alternatively emit from 4 or more thrust-ports at the same time.  This will be tested later, too.

(all of that stuff... somewhat depends-upon IF/NOT multiple GUI buttons (3+) can be held-down at the same time... touch-screen only.)

Full executeWhenReady project test:  https://www.babylonjs-playground.com/#PBVEM#193 

Lines 1690-1693... make the ps, set a texture, set a temporary emitter, and put it in the psTank.  Working good.  YAY!   Phew!   I wonder why ps.emitter doesn't default to v3(0,0,0) and thus not need to be checked in ps.isReady().  hmm. 

Some particles emit correctly from ONE port... with a translate RIGHT button (early tests).  Unfortunately, every time you press RIGHT button, the particleSystem emitPower increases. :o  Not sure why, yet.  It might be related to craft/emitter moving away from particles.  NULL TRANS button seems to fix it, temporarily, indicating t IS related to moving craft/emitter... but... it LOOKS LIKE TOO MUCH emitPower increase for the amount of craft/emitter movement.

Thx for the help/push, John!  That's what?  The 4th time you've helped me find a problem... by making a smaller PG for me? 

How do you do that, JK?  You're like a magician or something.  So cool.  :)

Share this post


Link to post
Share on other sites

Happy 201!   https://www.babylonjs-playground.com/#PBVEM#201

Got some basic thruster particles happening!  YAY!  They don't work real well with HELD buttons, but with clicks, they "spurt" nicely.

I am using momentary start-wait-stop particle methods, currently (lines 1845-1855).  I'd rather use .manualEmitCounts.

I will be trying... starting all particleSystems... with .manualEmitCounts = 0... and letting all 24 run continuously, soon. 

With no ps.emitRate, each thrusting just dumps a bucket of particles into ps.manualEmitCount, and they emit instantly.  poof!  Like a constantly-running confetti blower with a hopper.  Just dump confetti into the hopper, and out she goes... to the port.  :)

Early tests on that system... showed problems transitioning from color1->color2->colorDead.  Manually-emitted particles appeared to be mostly ignoring, or possibly blending color1, color2 and colorDead... into a new color... and using THAT for all the particles. 

Back in the old days (like last year), @Deltakosh and I determined that ps._scaledUpdateSpeed was causing some issues with manualEmitCount (seen 4 lines lower in the code).

SO, we did SOMETHING.  Somehow removed scaledUpdateSpeed from... what?  I dunno... maybe updateFunc?

We MIGHT have removed scaledUpdateSpeed activities on manually-emitted color1, color2, colorDead particle COLOR transitions (also part of updateFunc).

To summarize, I'm not sure if color1->color2->colorDead transition is working correctly... when using ps.manualEmitCount puffs... on a started particleSystem.  I will test more, and report.  (yawn)  :) 

Sneak peek:  #202  This one uses "more efficient" manualEmitCount hoppers.  Works great, and looking good for held-buttons, too.  YAY!!!  (Wingy dances.)

I was getting some out-of-memory Firefox crashes, earlier.  i hope THEY went away, now.  :) I'm too young to be "leaky".  heh

Also, color1/color2/colorDead issues (lines 1692-1694). (blue, blue, green).  My particles seem to go green before dead... but did we see a blue color1 and color2 as the particles leave the thruster port?  hmm.  I saw cyan the whole time.    I might need some min/max emitPower work... slow things down a bit.  :)  These particleSystems are zippy little machines... sometimes they get over-excited and rambunctious.  Ya need to gorilla-tape them to the ground plane... keep them from running too fast.

Also, my particles are spawning at the CENTER of 10-unit-sized boxes (ps min/max emitBox settings).  So, the particles are traveling 5 units before they pass thru the sides of the thrust-box, and into our view.  Still, seemingly wimply blues... for color1 and color2.  hmm.

Also, broken in my IE.  Darn!  hmm.  Line 1209 - Syntax Error, and little else reported.  Possibly line 1209 of shader code or something... because my line 1209 is camera.minZ = .1;  I guess I better stay with my Flyerfox ESR.   Errr... Firefox ESR, that is.  ;)

Share this post


Link to post
Share on other sites

Hi gang.  About 6 posts ago, in the "Long term thoughts" section, I talked about SKAP... station-keeping auto-pilot.  Essentially, it is a computer/algorithm that tries to "recover" an out-of-control spacecraft, using automated thrustings.   It is also used to "hold" that recovered attitude, if the SKAP remains ON.  When the SKAP is ON, user thrustings will be de-activated, most likely.

Whelp, I started it.  https://www.babylonjs-playground.com/#PBVEM#223

Lines 2111-2146... there's my "starter" Station-Keeping Auto-Pilot.

This version of the flyer... STARTS in a tumbling & sliding condition (lines 2210-2217 do that).

Press ANY of the 3 SKAP buttons on top, and skap() will run.  All it does right now... is periodically shoot some thrusts in all directions, and give us some angularVelocity (AV) and linearVelocity (LV) readouts on the bottom of the screen. 

But, WHEN the ACTUAL skap algorithm is REALLY coded, it will probably cause spurious thrustings similar-to those you see in this demo version.  The skap will very-often/continuously "poll" the flyer AV and LV values, and use the thrusters to TRY to stop the craft from position-sliding and rotation-spinning.  FUN!

Ok, that's all I got, so far.  I'm a little scare of writing the actual skap() code.  Do others want to try it?  I'd welcome ANY attempts.  (thx)

Remember, we MUST use the thrusters to stop the sliding and rotating.  No physics impostor-damping or other vector3-forcing allowed.  :) All the available thrusters are already listed in the SKAP() func, so you can see how to call them.  I think 1/3 of-a-second updating is fine.  Since the skap checks for progress every 1/3 second, it is likely that certain thrusters will remain ON thru 10-40 1/3-sec update checks.

It is possible that it COULD take up to a minute of SKAP thrusting-work... to get the flyer "under control".

In outer space, it is not easy to determine what is UP-vector/direction.  Please use the scene's UP as the flyer's UP.  For rotation, not only do I want the rotation nulled-to-zero (as close as possible), but I also want the flyer as close to UP as is possible.  Perhaps "rotate to scene UP orientation"... is an "after tumble recovery" late-thing... an optional thing.

There MAY BE (likely) some residual angular and linear drift... after the SKAP has completed its HEAVY work.  After that heavy work is done, it would be good to STORE the current flyer position and Quat-rotation values.  I would like to allow the SKAP to continue monitoring drift... and if the drift gets TOO FAR from stored position and quat-rot, it tries to correct it.  That's what station-keeping is all about.

In a way, we are "abusing" the station-keeping auto-pilot (skap)... by asking it to do flyer out-of-control recovery.  :) It's part of the fun.  :)  Any takers/helpers?  I could use all the assistance that is available.  (thx)

And, I'm still getting some occasional Firefox out-of-memory crashes. (caused by quality Wingnut coding, I'm sure)  :D   Hmm.  Any help with that... is appreciated, also.  I suppose I should try to "profile" this thing with my browser dev tools.  Scary.  :)   It's SUCH a big fat pig, eh?  I'm SO proud.  heh.

Share this post


Link to post
Share on other sites

Hi again, girls.

https://www.babylonjs-playground.com/#PBVEM#232

(Firefox and Safari only, afaik.  Last I checked, it fails in IE.  Other browsers not yet checked.)

Having some fun with "rotation recovery"... lines 2157 - 2166.

            bobsled.interval = setInterval(function(){  // every 1/3 sec.
                av = bobsled.handle.physicsImpostor.getAngularVelocity();
                lv = bobsled.handle.physicsImpostor.getLinearVelocity();

                if (av.x > 0) bobsled.controller.rotNegativeX();
                if (av.x < 0) bobsled.controller.rotPositiveX();
                if (av.y > 0) bobsled.controller.rotNegativeY();
                if (av.y < 0) bobsled.controller.rotPositiveY();
                if (av.z > 0) bobsled.controller.rotNegativeZ();
                if (av.z < 0) bobsled.controller.rotPositiveZ();

Only doing rotation recovery, so far.  Linear/translation recovery comes later, and it MIGHT require that rotation recovery happen first.  Not sure yet.  Anyway...

Run the PG, and then hit ANY "skap" button.  You'll see the auto-thrusting start, and you can watch the progress with the AV: display near bottom of screen.

I've seen it work properly... ONCE.  The other times, it seems like there is some type of "over-shoot".  hmm. 

The skap auto-pilot seems to get NEAR-to 0,0,0 Angular Velocity, but then, most times, AV starts increasing again.

Anyway, it's almost fun to watch the rotational thrusters and the AV numbers.  If anyone has ideas for improvement/repair, please speak-up.  thx.

Update:  Slimmer version, #239 ... keypress-listening and bobsled model removed, just the master handle... the lone physics object.  SKAP code is at lines 1330-1344 area... still SOMETIMES working, but often "overshooting".  Objective... run PG, press any SAKP button, and auto-pilot should stop box rotation.  AV: numbers should go down, down, down, and stay low.  But usually, they go low and then start climbing again.  hmm.  I think my thruster functions are fine.  Puzzling. 

It's as-if, at a certain point of slowed-rotation, all my thrusters start working in the opposite direction, and begin INCREASING the spacecraft tumble.  DARN!   hmm,  I'm calling NASA, see if they'll help.  :)

Share this post


Link to post
Share on other sites

Yay!  https://www.babylonjs-playground.com/#PBVEM#246  (Read recent older posts in this thread... to catch-up with "the story", as needed.)

Just RUN it, box (spacecraft) is automatically randomly tumbled.  3 seconds later, the station-keeping auto-pilot (SKAP) turns on, and you can see the thrusters go to work.

Watch the AV: numbers (angular velocity).   Larger numbers... reduce faster, smaller numbers... reduce slower.  More on that, below.

So far, it does successful tumble-recovery ALMOST every attempt  (It takes a while, though... dependent upon amp power-scaler variable - line 1332.)

When the SKAP has attained station-keeping (tumble-recovery)... it automatically shuts off.

Lines 1330-1355 is where the fun is at.

For those who are following closely and wanting to know the technical mods so-far (nobody)...

                if (av.x > maxResidual) { bobsled.controller.rotNegativeX(Math.abs(av.x*amp)) };
                if (av.x < -maxResidual) { bobsled.controller.rotPositiveX(Math.abs(av.x*amp)) };
                if (av.y > maxResidual) { bobsled.controller.rotNegativeY(Math.abs(av.y*amp)) };
                if (av.y < -maxResidual) { bobsled.controller.rotPositiveY(Math.abs(av.y*amp)) };
                if (av.z > maxResidual) { bobsled.controller.rotNegativeZ(Math.abs(av.z*amp)) };
                if (av.z < -maxResidual) { bobsled.controller.rotPositiveZ(Math.abs(av.z*amp)) };

While SKAP is active, this section gets run every 1/3 second.  Feel free to adjust that "thrustActionManager" polling-rate... in line 1381.  ;)  Triggers and actions, and rates of checking.  I wonder what the polling-rate is... for BJS observers.  I suppose that depends upon how many of them... are triggered and need actions (seeing we're not multi-threaded).

Power scaler:  I added a parameter/feature to my 6 thruster funcs... amount of power (throttle setting).  Variable throttle settings on thrusters was NOT part of original intended flyer design.

Var amp is just a scaler/amplifier... multiplies all thrust-forces by 15, currently.  (yawn)

What this does... is counter-thrust MORE... on axes with LOTS of spinning, and counter-thrust LESS... on slower-spinning axes.  (no matter spin-direction)

In other words, doing this... attempts to "equalize" the spin on all 3 axes.  It slowly tries to make all three axes spin at the same velocity (without accelerating the spin on ANY axes).

This has somewhat reduced the "overshoot" problem I had with rotational SKAP in earlier versions.  Translational SKAP (linearVelocity) will probably use the same method.  I will counter-thrust hardest.... against the axes with the most velocity.  I'll counter-thrust less... on axes with lower absolute velocity values.

Phew, I'm glad I'm finally making some progress (but maybe not - see below).  It's nice to see rot-skap work fairly-consistently.   Feel free to adjust the values in lines 1332, 1333, 1381, then re-RUN, and watch the tumble-recovery system... change characteristics. 

I HAVE seen some fails, though, so, I'm still worried (experimenting with amp = 20 and maxResidual = .01).  Same crap... a type of "overshoot" of station-keeping - an "almost". 

After overshoot/fail happens, thrusters act like they are reversed, and ADD TO the spin velocities.  Not sure why, yet.  A tough puzzle to solve!  If I solve/fix WHY the thrusters act backwards (after over-shoot/failed SK), then the future SKAP will auto-compensate for any overshoot issues. 

That's what it is supposed to do.  If the numbers in the av: start increasing, the SKAP should grind them down... no matter what.  Currently, after over-shoot/fail, the numbers keep going up and the spin goes crazy.  :o

In a way, this "thrusters-with-throttles"-solution is "illegal".  The thrusters on the flyer were never intended to have on-the-fly variable thrust force (throttle).  They are supposed to have a SET pulse power.  And each is either ON (single-pulse or held-button pulse-repeating), or OFF.  Soooo... hmm.  The NEW solution... would be to adjust the length of TIME a thruster "runs" (pulse-repeats)... based upon the amount (severity/magnitude) of tumble (angularVelocity) on each axes.  hmm.  Faster-spinning axes... get longer-run-time counter-thrusting.  How the heck would I do THAT?  :)

Also, any GOOD space engineer would NOT counter-thrust HARD against the fastest-spinning axis (...of a tumbling spacecraft).  IF ANYTHING... the fastest spinning axis would get the most-gentle counter-thrusting... and enjoy a "take your time"-attitude in bringing that fast-spinning axis to a stop.  That's the opposite of what I am doing.  *sigh*  I have work to do.

In real-life spacecraft, and depending-upon mass and thrust-power, it is possible that an auto-pilot tumble-recovery... for a severely-tumbling spacecraft... could take an hour or a half-day.  If it is a spacecraft with a crew, there will be lots of vomit to clean-up, when station-keeping is attained.  :D

Share this post


Link to post
Share on other sites

Hi girls.  A little update on the SKAP tumble-recovery auto-pilot, as well as the new automatic "orient" auto-pilot.  (skap - station-keeping auto-pilot)  (tumble-recovery)

https://www.babylonjs-playground.com/#PBVEM#292

Just RUN it and relax.  Spacecraft is auto-tumbled, and SKAP func (lines 1318-1371) auto-activates after 3 seconds.  It uses a combination of throttled thrusting, and a tiny bit (more) of physicsBody angularDamping.  So far, I have not seen the SKAP phase fail.  You can watch the av: numbers (angular velocity) as the skap "grinds" those numbers toward low magnitude values.

When SKAP reaches a reasonable threshold of tumble-recovery... it shuts off.  3 seconds later, auto-orient activates... thrusting the spacecraft toward 0,0,0 on the erot (euler rotation) and qrot (quaternion rotation) values.  It takes a while, and it is NOT perfect.  But, if I ask it to be MORE perfect-resulting, it takes even LONGER.  So, it's a trade-off.  Most astro-crews probably don't care if they have a tiny bit of angular drift... at the end of a short auto-orient function.

It seems to work pretty well, but SKAP phase COULD still fail... sometimes.  It's "on the fence"  :)   Maybe that's part of the fun of the game.  SKAP failures happen when the craft is ALMOST PERFECTLY done spinning... but then the av numbers start increasing again.  I have not figured out WHY that happens.  But, all in all, I can programmatically "watch for" indications of a SKAP about to start failing, and have it shut-off the SKAP immediately (prevent craft from slowly re-entering violent tumble again).

I am still in search of the reason WHY SKAP failures happen.  I think you can promote more SKAP failures... if you remove line 1351, and increase amp in line 1337... to perhaps 15 or 20.

At a certain point of slow angular velocity and low rotation, the whole thing reverses... and my thrusters appear to start INCREASING angular velocity, going against their code logic.

Interesting note (yeeeah):  If I see the av: numbers start increasing, and manually shut-off the SKAP (by clicking any SKAP button)... then wait a few seconds, and click a SKAP button again (to re-start SKAP)... the "backwards-ness" is STILL there.  The SKAP thrusting starts increasing the tumble speed.  Bad, bad, bad.  I wonder what causes this "suddenly, all my thrusters work backwards" problem.  hmm.

See lines 130-138?  It's a cool little function that DK showed me.  What it does... is calculate the very-current rotation/orientation of the craft.   EVERY TIME I generate a physics translation impulse, or two rotation impulses (I "twist" the craft with 2 opposed'n'offset physics impulses... to cause a rotation thrust)... this function gets called.  EVERY thrust pulsing!

I dunno IF or WHY this function would/could "invert"... where it starts doing everything in the opposite direction... but that's my best suspect so far.  SKAP works just fine... thru its "coarse" phase... counter-thrusting almost all angularVelocity magnitudes... using only thrusters and EVEN with UN-throttled thrusters. 

I hate (highly-dislike) setting/varying throttle values on the thrusters.   It seems like cheating.  By initial design, they are supposed-to always thrust at the same set power. 

But noooo.  Ex:  Line 1344... the Math.abs(av.z*amp) portion... is a thruster throttle-setting value.  (Wingy pokes it with a stick and hopes it will leave).  :)  It should probably be Math.abs(av.z)*amp, too, but I guess that doesn't matter.

ANYWAY... when the SKAP starts working on the "vernier" phase... the little-thrustings.... the final tweaks... THAT'S when I see the SKAP sometimes start failing.  Most/all the av: numbers start increasing instead-of decreasing.

SO, this persistent and annoying "thrusters suddenly start working opposite when av values get low" -problem... is still a huge issue and a major puzzle.  All help welcome.  Thx.  Click here for 2 meg .zip of entire box-flyer package - no keypress observers - no spacecraft model attached.

Meantime, I think I'll start working on linearVelocity SKAP now... when the craft is changing position at an insane rate.  Just possibly, I will need to ensure the craft is NOT TUMBLING... before I can begin counter-thrusting the unwanted translation.  So, rot-skap first (but maybe no auto-orient needed)... and then lin-skap.  Then orient.  Complete vehicle insanity-recovery.  :)

It's not like any of us would EVER pilot a spacecraft... in a way that would cause it to tumble violently thru space, right?  Nah.

Update:  #295 is ready.  PG starts with craft tumbling and translating uncontrolled.  Click 'Rot Skap' and wait until that is finished.  After that, you can click Trans Skap or Orient in any order, and maybe at the same time.  Do Rot SKAP first, because Trans SKAP does not work well... while craft is tumbling.  All 3 buttons are toggles.  Old 'null rot' and 'null trans' buttons are still active... for instant-stop, as wanted.  Trans-SKAP is brand new... and fails often... same problem as rot SKAP... thrusters sometimes operate in wrong direction.  Still testing.

Share this post


Link to post
Share on other sites

Hi girls.  Newest flyer tests... https://www.babylonjs-playground.com/#PBVEM#300

Warning:  This might drink memory/threads or something.  My CPU fan often speeds-up, and/or sometimes I see some long/frequent garbage collection pauses.  :)

This PG tests "positional autopilot"... the most common kind.   This version works in my IE, too!   [Avoid using ()=> function shorthand stuff in IE.]

Just run and relax.  Watch the pos (position) and lv (linear velocity) numbers.

The flyer starts in some random position, and 3 seconds later... the thrusters start trying-to fly it HOME (0,0,0).  It will auto-pilot to any target... but I have it set to home... for now.

The home() func is lines 1552-1629 and is rather complicated.  This is a "least efficient" auto-pilot in that it does ZERO "coasting".  Essentially, it goes full thrust half way to its target, and then fires braking thrusters the rest of the way.  When it gets within about 5 units, it "resamples"  the distance between the flyer and its target... and keeps trying.  (Boy, could THIS thing use some recursion, eh?  I wish I wasn't scared of recursion).

It's doing a pretty good job of taking us home, but it doesn't like to shut-off when it arrives.  I'm still working on that.  Just click the 'null trans' when the flyer has reached its target and won't shut-off.  :)  Also, it might be wise to avoid pushing the trans skap button right now.  He appears sick.  :)

Look at lines 1554-1560:

var brakingpoint = .50015;
var resampleDistance = 5;
var target = new BABYLON.Vector3(0, 0, 0);
target = target.negate();
var startpos = craft.handle.position;
var diff = startpos.subtract(target);
var maxResidual = 1.25;

What a friggin' nightmare, eh?  No wonder NASA wouldn't hire me, even as a janitor or grounds keeper.  Too many ugly variables could come WITH me.  :)

BUT... notice I did NOT "throttle" the thrusters in home()!  YAY!  Remember how I HATE up/down throttling of the thrusters, and wanted them be ONE static pulse-power?  But I needed to adjust throttles... for the ROTATIONAL tumble-recovery autopilot and also for "auto-orient".  With the "resample occasionally along the way" method I used on this trans AP... I MIGHT be able to turn OFF throttles for the rotational autopilot stuff.  YAY!!

Where's a space engineer when ya need one, eh?  *sigh*

I think I need recursion... for ALL of it.  Not sure.  Seems maybe so.  (Wingy's dog crawls inside of a Jack-o-Lantern to hide.)  :)

As always, I welcome better auto-pilot code.  Ya gotta like pain, or else don't bother.  heh.

Share this post


Link to post
Share on other sites

Hi gang!  Well, here ends The Wingnut Chronicles, and this forum. 

  • 1,459 replies
  • 96,174 views

Not quite 100,000 views, but close.  :)  This forum is going READ-ONLY soon, so maybe the views will still increase into 2019. 

Come check out our new forum at... https://forum.babylonjs.com/

I'm still on the road to the new forum.  I snapped some pics...

http://urbanproductions.com/wingy/ipad_snaps/ip04/viewer.htm

By the way, good whiskey helps... for getting a lens flare un-stuck from your tongue.  :)

Cya at the new forum!  It ROCKS!

Share this post


Link to post
Share on other sites

@JCPalmer  Yuh, yuh, yuh... you are correct.  Why do you think I'd try to "munch" a lens flare?  See my eyes?  Roadmaps, baby.  heh.

The lemon wasn't bad, but... I think I like "Master K" better.  We really love skunks 'round these parts.   Indica-tive, ya know?   But transporting skunks is was risky.

I have SO many new things to learn/try, but the stores won't be opening until 2020, I hear.  hmph.  

But yeah, a new feeling of freedom has come-upon our state.  I hope it comes to other states, too.

Off-topic?  Does it matter anymore?  :D

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.