Jump to content

Solid Particle System Collisions?


dbawel
 Share

Recommended Posts

Hello,

Is it possible to use collision detection to have an SPS avoid an area in the scene? Either this, or perhaps a large # of sprites?

And @Wingnut - as I mentioned, I have a couple of simple solutions to the dynamic texture text post from more than a wekk ago, but I'm only back on the forum after a stay in the hospital at death's door with salmonella poisioning( as I waited too long for treatment - thank God my Wife is smarter than I am.) I'm pretty much recovered now, however I pretty much wish I were dead for a few days while in treatment. So I expect to finally build a scene tomorrow which I hope meets your expectations of "simple."

But as for collisions, I need to use sprites or meshes which I can attach a videoTexture to their material and animate (possibly flock) at least 200+ meshes or sprites, etc. and have them avoid an area in the scene - perhaps using a spherical bounding object to define the area they must avoid - not bounce off from a collision necessarily. So I don't necessarily require collision detection, but need to avoid a defined area in the scene.

Any thoughts on the best method to accomplish all of the above?

Thanks,

DB

EDIT - actually, the client just changed the specs of the project at the last minute, and I now require collision detections and reactions (changes in translation and velocity from collisions) between the SPS meshes, sprites, or whatever objects can poulate an area with 200+ objects such as in the SPS demos with a good FPS, but also can each have material channels for textures (not necessarily videoTextures, as I'll most likely use multiple 32 bit textures and alpha channel transparencies) and animate the textures such as translation and scale to make them all apear unique. So each object must utilize collision detection, and also detect and react to at least 2 spherical bounding objects which can move with the user's fingrs when they touch the screen - and the collision spheres (two or three) must also not intersect as they need to also avoid collision suing collision detection, but these are invisible to the user, so I'm less concerned about this - but concerned about populating the screen with 200+ textured meshes capable of avoiding collisions with each other as well as the  2 0r 3 invisible spheres which I'll scale when the screen is touched by the user for the 200+ translating objects (SPS meshes?) to react to colliding with these as well.

As I believe @jerome was instrumental in developing the SPS, perhaps he might read this and let me know how screwed I might be - but I would guess he might also have the answer to my potential dilemma.:)

Link to comment
Share on other sites

I did what?  When?  If it's more than 3 bhong hits ago, I've forgotten all about it.  :) 

Ohhhh, the different font family/size for each character and removing one character at a time with the backspace, without having to rewrite the entire text string?  Oh, that's just something to do if you don't have enough pain in your life.  :D  Sounds to me like ya got plenty of pain on your plate.

So, sigh, what's the deal on the food poisoning?  Holy crap!  That's terrible!  Don't do that anymore, okay?  :/  Too late for the stomach pump, and had to ride it out through the blood stream and digestive system, huh?  Oh goody.  Complete system flush, and re-install operating system, eh?  Yech!  Sorry to hear that, DB.  Phew.  What a grind!  Good to see you still alive.

On that other front, just punch that client in the mouf, and do whatever YOU want to do.  (unless they are nice folk.  then you should prolly give it that good ol' college try).  :)

Always remember... a "requirement" is just a pipe dream that you haven't yet spanked brutally and re-labeled "a ridiculous idea".  :)  Make sure your contract states that you work "with" them and not "for" them.  Make sure you place just as many orders as you fulfill.  Stay on level ground, or completely dominate them.  Keep them scared, and don't let them see you blink barf from food poisoning.  I could tell ya some stuff about the amount of servitude seen in capitalism, but... no, better not.  All in all, never give away your power... unless you're on the ropes, nuts in a vise, or over a barrel.  (where most of us reside 24/7).  heh.

Ok, ok, on-topic... I got nothing... except perhaps something that looks like a Jerome thing...  The Sphere of Triangles - http://www.babylonjs-playground.com/#1LIVJD#4

I kind-of like it.   Hey DB... DON'T EAT IT!  ;)  I'm quite sure mesh are not nutritionally beneficial... and the corners of those triangles won't "pass" well.  :o  Ouch.

Link to comment
Share on other sites

Hi @dbawel,

I wish you feel better very soon.

The SPS doesn't provide for far any mechanism for internal collision detection (collision between its own solid particles). As a standard mesh, the whole SPS can obviously collide with other BJS meshes the standard way.

Nevertheless , if you don't want to implement your own collision detection mechanism within the SPS (what is understandable because it's a huge work... I need to think about it), you could ever rely on some physics engine and attach each solid particle to an impostor. You will then get an out-of-box working colliding mechanism. @RaananW did some PGs with some SPS solid particles relying on oimojs collisions... but I can't retrieve the posts :-(

Link to comment
Share on other sites

another idea ...

If you don't want to create your own collision system from scratch AND you don't want to use an external physics engine, the approach could be to use some internal BJS tools like the method : mesh.intersectsMesh(otherMesh)

Have a look at the code here : https://github.com/BabylonJS/Babylon.js/blob/master/src/Mesh/babylon.abstractMesh.ts#L797

it just calls under the hood : boundingInfo.intersects(otherBoundingInfo)

This means we could just create a BoundingInfo per solid particles according to their respective dimensions and then call the intersects() method over all these boundingInfo objects.

Anyway note that computing collisions between 200+ objects will be a huge loop : check for each one against the 200 others

Link to comment
Share on other sites

you're right

my suggestion was simply to re-use some internal function and to use a simpler colliding system than the one provided by an external physics engine (I shoud have written this before) by computing on AABB BBox intersections only, what would probably be enough for a big amount of solid particles ... rather than real, say, more realistic collisions, impostor-based (so, not only BBox, but spheric, cylindric, or what ever) like a physics engine can provide.

Link to comment
Share on other sites

@Wingnut - Yes, I simply had to ride it out - mostly with IV fluids and am still on Antibiotics for another week simply as a precaiton; since there's no indication these actually have or are assisting with my recovery in any way - although I feel fairly normal now for the most part. I don't recommend eating fresh fish from food carts in TJ which I've never personally tried previously, as I have several close friends who own a few of these carts, but this time simply threw caution to the wind - so this one was my fault at best. Howevr, I've NEVER gotten ill from eating on the street in Mexico in more than 20 years of regular travel to visit good friends as well as our God Daughter - who is now almost 6 years old and a real joy.

So I expect that I deserve at least a couple good weeks now, as the pain and discomfort I felt was far beyond any other illness I've ever experienced or might ever have imagined. Thanks for your kind words, and as for the Dynamic Texture Text scene, I have a reasonably "simple" solution, with the exception of consistantly using backspace without adding additional characters under certain circumstancs - specifically drawing "zeros" depending on the circumstance. But I expect to solve this when I take a break from my real work shortly, as the reason for this is an obvious one.

@jerome, @fenomas, and @adam, thank you for your feedback. I'm currently considering oimo as perhaps the most obvious solution at this point. However, will oimo work with an SPS, and are there limitations to using several different textures on SPS meshes? This is somethng I'd love to have an answer to and will begin testing, however if @jerome already knows the answer to this, then it will save me considerable time to test - which I have no issues in doing so, but perhaps there is an approach and/or a method I haven't yet considered which might have a chance at simplifying the scene as well as reducing collision calculations - which is why I'd love to try and utilize an SPS as this would certainly simplify much of the scene overall.

Also, does anyone have  one or more PG scenes with a large # of simple meshes all ustilizing collisions with each other? I've done extensive searching, and have yet to find a PG scene with any # of textured meshes beyond a simple few calculating collisions. So if a PG scene exists with more than a few textured meshes utilizing collisions, it would be incredibly valuable to review as I'm almost certain there might be an approach I'm not familiar with in propogating a large # of textured meshes calculating collisions; as I've spent very little time suing any physics and/or physics extensions in BJS. I'm also considering utilizing Web Workers for collision calculations as @RaananW covered this in a 2 part article (which I highly recommend everyone reviewing) which appears to solve the asynchronous rendering speed and collision calculations utilizing an IndexedDB. But again, this is something I have virtually no experience in building, and might perhaps blow my delivery schedule if I begin to head in this direction. So any further thoughts on any of the above topics are very welcome, and again I appriciate the input already provided. However, any PG scene which even remotely demonstates calculating collisions for as many textured meshes as possible I would expect might help me a great deal. If not, any suggestion on how I might approach this beyond the obvious using Oimo as an example would also be invaluable - and perhaps utilizing instancing? I'm beginning to test different approaches now, but perhaps I might be overlooking an obvious and much simpler approach to building such a scene as described requiring considerable collision calculations as well as variations in textures.

And if I might make a suggestion, I believe it would be very valuable to add a "text field", rollover, etc. which allows users to add a very brief desciption of each PG scene when searching through them. The reasonably "new" search feature is a huge help to all, however adding a brief description to each scene would be invaluable to me and I would guess to other users as well - as it's simply  hit or miss in serching for specific examples on the PlayGround with only vrsioning to help guide us through a search. Just a thought.;)

Thanks,

DB

EDIT - FYI, the 2 part article I found very valuable written by @RaananW discussing the use of Web Workrs for calculating collisions in a BJS scene can be found here: https://blog.raananweber.com/2015/05/26/collisions-using-workers-for-babylonjs/ and as mentioned, I highly recommend reading through both parts as they are full of very valuable info for using Web Workers in general, but his pproach to solving the issues with asynchronous calculations vs. the rendering engine provided me with a great deal of guidance for this and other projects. And it's obvious that allot of thought and work went into writing this.

Link to comment
Share on other sites

quick answer : a SPS is a BJS mesh, so you can use textures like you would do with a mesh : one emissive texture, diffuse texture, bump texture, texture arrays, etc

but the SPS provides a little extra feature, because you can access some parts of a single initial texture and assign them to each solid particles. In other terms, you can use one texture file as a texture atlas and set different images (textures) to different particles within the same system

http://doc.babylonjs.com/overviews/Solid_Particle_System#uvs

Link to comment
Share on other sites

@dbawel: To be honest I think you have the cart before the horse here - in talking about, say, how to get oimo to drive SPS particles (which I expect would not be very easy), or doing collisions in workers, even though your original post says you don't necessarily need or want physical collisions.

I would strongly suggest that you should start by creating the effect you want without considering performance or implementation details. Just make a bunch of regular meshes, with regular materials and textures, and either drive them with oimo, or move them all manually from one big beforeRender callback, or do a combination of both. If it runs too slow with 200 meshes, just lower the number while you work out the effect.

Once you're happy with it, then check if it's slow. If so, you can profile to figure out what optimization you need. For example, if checking for collisions is the bottleneck using SPS or instanced meshes would be wasted effort. (Also, 200 isn't a huge number of meshes, so you may well find that everything performs fine and there's no need to even consider optimizations.)

Link to comment
Share on other sites

@RaananW please, could you retrieve and show us the PG demo you made once with animated colliding solid particles powered by oimojs ?

I remember the code was quite simple, basically creating a box impostor per solid particle in the loop initializing them.

 

[EDIT] I guess that Raanan will meet this challenge again, he will let you know when he retrieves his cool PG

 

Link to comment
Share on other sites

@jerome - Your advice to use regions of single texture is something I had overlooked - duh! - and as usual, find it difficult to imagine that I didn't even consider this, as it's very obvious, but wasn't at all obvious to me until you posted this.:blink:

I have searched high and low for a PG scene using and SPS with Oimo, so if @RaananW or anyone is able to provide such a link, this would help me considerably in my quest to potentially find the best method to accomplish my current task - especially since most every user on this forum generally uses different methods to accomplish similar scenes - and I'm certain that @RaananW among others would provide elements of code and methods I most likely haven't yet considered; and would increase my skill level in learning how they approached the same issue.

As usual, I am grateful to have this forum as a resource and to be a part of a community in which I've yet to find any regularly involved developer on this forum with ego issues, or who is in this strictly for themselves; as I've often found on other communities and forums. Not to mention the dis-respect often seen between users and in their online dialogues. And recently, I've personally been able to convert 3 developers who were strict Three.js advocates to begin using babylon.js for their most recent projects. None are games, however all 3 now have their sights set on potentially building games in the near future using BJS, and all have been very happy with the Dialogue extension as well as canvas2D for a foundation in building functional GUIs. So they're still exploring, however all 3 are seriously considering making the move to BJS with other new projects on the horizon. Obviously, I've heard a few complaints, however these have generally been simplistic in nature and none have yet to cause a road block to anything they've found to have issues in building. So again, I'm personally grateful for all help and input, and as I continue to improve my skillset through topics such as this, I'll be passing all knowledge to the next newbies - in which babylon.js is now beginning to grow like wildfire. 

I hope @RaananW is able to post his PG scene utilizing Oimo along with SPS, as this will provide me with far more info than I'm currently finding on my own currently, and should accellerate the overall process towards finding the best method. Regardless, I have to focus on the basic client sign-off today, and will dive in this weekend to make further discoveries and improve my skills in this area which I have virtually no experience using physics and collisions in BJS. My personal experience goes way back to an application named Dynamation before Alias/Wavefront aquired them - look this up online if you have the time, and you might see how dificult it was to build scenes such as the final ship explosion in the 5th Element - which pushed the limits of my abilities at the time. And I literally paid exactly $10,000 US for a single license in 1998, which I'm now able to utilize physics tools (such as Oimo.js) which are far simpler to use than what I had to go into debt to obtain and use - not to mention the hardware costs (oh my God!) - and not so long ago (at least for me - in dog years.) So I hope everyone understand that when I talk about how grateful I am for the hard work and effort which many people have been and are putting into building the tools and framework we use, I mean this with all conviction. And my opinion that babylon.js is the best framework currently available to use professionally, I am a true believer.

Cheers,

DB

Link to comment
Share on other sites

I'm confused.  :)

Ok, SPS... is a single mesh.  http://www.babylonjs-playground.com/#2FPT1A#36

scene.meshes.length = 2 

So, we must be careful here.  When Jerome says that SPS is just a mesh... he does not mean that EVERY SPS particle is a standard mesh.  Right?

Soooooo... the only physics imposter you can use on a SPS... is a Cannon meshImposter...  or... a big fat compound (a 'structure' of many simple imposters such as the Oimo heightMap car demo).  Yes?  And it would be one giant imposter... no particleshape-to-particleshape collisions allowed, I suspect.

I like Fenomas' idea.  Just get a pile of real non-SPS boxes, and run some tests.  From what I have seen so far, BJS colliders don't enjoy having more than 1 mesh... in collision simultaneously. 

The physics engines... handle multiple collisions somewhat okay, but you pay for this in performance.

And I suppose the ABAB vs. OBB (precise = true/false) seen in our intersections playground demo... is important to performance, too.  *scratch scratch*

There is not a bounding box around each individual building in the #36 city.  Where am I going with this?  I dunno.  Sniffin' around... thinkin' about fish carts, I guess.  :o

Link to comment
Share on other sites

I'm currentlt thinking about some feature to detect solid particle intersections between them or (if possible) with any other mesh. Some kind of extension of the intersects() method.

I'll keep you posted if I can achieve anything pertinent.

NOTE : this would just be the detection of intersections, not any colliding system what is more related to physics. I want to keep the SPS physics agnostic.

Link to comment
Share on other sites

_particle._modelBoundingInfo.boundingBox.vectors   wow!   The "Bousquie Bounding Box"!  :)   Little tin lunch-boxes for each particle shape.

Can we get Claudine Longet pictures on those lunch boxes?  I think that would be a good place to store my Saucisse de Morteau.  ;)  oui oui

Link to comment
Share on other sites

@dbawel will take care of the playgrounds.  :)

heh.  ahhh.  I sure am funny.  Okay, so... let's see... LOT's of people participated in my "observables" campfire discussion, which I tried to lure people-to... in the Wingnut Chronicles.

I wonder how observables can be involved in intersections.  I bet they can work together.

Ever ponder that we would love to be able to "deduce"... the direction of movement (both for the intersectOR and intersectEE)... that caused the intersect?

I don't think that is possible.  Soooo... what use is a particle intersection sensor/event?  We can't do colliding/rebounding.  All we can do is... what?  Change a color?  Make the asteroid break-into multiple pieces?

We don't know the fastest way to get the two particleModels OUT-OF intersection.  We could dispose one of the particles, but SPS particles don't do disposing, right?  They just return to the pool, yes?

Just thinkin'.  hmm.  I think DB will need collision and rebound... and it seems a LONG WAYS AWAY yet, huh?  (for SPS)  Possibly implausible?

Link to comment
Share on other sites

@Wingnut - Actually it's very plausible - just math. The following book explains it fairly well - but this is a simple link (missing pages), and the book needs to be purchased to have all of the math handed to you: https://books.google.com/books?id=foPmfKgipwYC&pg=PA131&lpg=PA131&dq=webgl+apply+constant+velocity+physics&source=bl&ots=XzScK3q9GK&sig=fhrd6BpKn3KlmvnyYc34Iq5dAQw&hl=en&sa=X&ved=0ahUKEwjb8qiz4NbPAhVENz4KHXA1AJQQ6AEIPTAF#v=onepage&q=webgl apply constant velocity physics&f=false

So before and during my severe illness, I was considering utilizing a SPS for my current project - but as you might have seen in my other posts, I decided on OIMO and battled with oimo.js for a week until admitting that oimo.js is not functioning at all in babylon.js 2.5 currently - and I tried every possible attribute and additional functions to get it working - as I assumed it was my deficiency causing the severe bugs in my scene. So following my last topic on oimo.js which determined it was broken:

And following @fenomas also discovering that oimo is not currently working at all, I switched back to cannon.js and all appears to be well. However, I still see a bright future for SPS, and am certain it will be of great value to future work - especially as new features are added by @jerome or contributed by others. All I can say now is that I'm set on physics currently, and I've got that goin' for me:blink: as the schooling was long overdue.

So thanks to everyone for all of your help these past couple weeks, and thankfully cannon.js is again doing most of the heavy lifting for me. I hope someone wiser than I can solve the issues with Oimo, as it's always best to have more than one viable solution - which is why I look forward to the SPS updates.:)

Cheers,

DB

Link to comment
Share on other sites

In the SPS, the particles aren't disposable in term of still belonging or not to the pool, but you can set them invisble or not (particle.isVisible) and process it or not (particle.alive). An invisible particle no longer processed is the best way for now to consider it as "disposed".. and it's still avalailble in the pool for further use.

The SPS doesn't know anything about physics. You can use any of the physics engine pluggable to BJS for the particles (just create an impostor for each one and apply physics, too bad that Raanan didn't retrieve his demo with SPS+oimojs) or you can implement your own behavior. Indeed, when a particle intersects another one, you know both positions and both velocities (and other particle properties if any, like mass, scale, etc). So there's a way to give your particles, from these known values, some expected behavior. If particles are really ... particles, I mean small objects, this should be enough as the impact position on the particle surface doesn't really matters. I'll check in the next days (weeks) if it's worth to implement the intersection point reagrding to the complexity and the performance that stays a serious consideration when dealing with thousands of objects. 

Link to comment
Share on other sites

Thx guys.  Yeah, I wasn't thinking about physics engines at all.  Just onIntersect, and then clearing the intersect as fast as possible.  I guess... if we have the velocity (direction vector + magnitude?) for both particles involved, then we can set a new (tangent?) velocity  on both particles (a rebound/restitution) and then the 2 particles will clear their intersect... within a frame (particle update) or two. 

Sort of like the cannonball ground-bounce that you did for that cannon, right Jerome?  Ball impacts ground at a certain velocity/angle, and the NEW velocity/angle is based upon the velocity/angle at the time of intersect/collide.  The intersectExit velocity could be derived from the intersectEnter velocity.

It would take one particle position update to ENTER an intersect.  Under certain circumstances, it might take 2-3 particle position updates... to EXIT intersect, even if the same ENTRY magnitude of velocity... was used for the exiting velocity, right? 

In other words, a single particle position update... might cause two particles to have a 50% boundingbox overlap.  The quickest way to EXIT that intersect, is to negate/invert the velocity of the particle, and use the same magnitude (full reverse engines).  If the magnitude or angle of the exit velocity was not perfect inverse of the entry velocity... it might take TWO (or more) particle position updates (after reverse engines)... to exit the intersect.  We cannot re-check for intersect until the particles have de-overlapped, or else we would get a false intersect, because the two particles had not yet separated from the previous intersect.  The exiting particle hasn't had sufficient time/velocity to exit from the first intersect, yet.

The exiting particle might have 40% overlap on the next frame, then 20%, then 0%.  It could take 2-3 particle updates before the two particles would de-overlap.

If two particles intersected at high velocity, their two BB could be 90% overlapped.  David might say to himself "Ok, I have intersect.  Time to build a bounce/rebound/deflection."  So he might calc a new velocity vector and then the particle position update moves it AWAY FROM intersect.  But if he used only 25% (example) of the inbound velocity... for the outbound velocity, the particle might not clear the intersection in one particle update.  It might take 2-3-4-5 particle position updates... to get the intersect cleared.  During those 2-3-4-5 updates, he cannot check for intersection of those two particles, because they will show intersect... but it is an OLD intersect that hasn't cleared yet.

With me?  If so, you guys are doing better than I, because even I am not with me.  :)

http://www.babylonjs-playground.com/#1ND6TH#15

Oimo works a little bit, yet.  There is an unwanted constraint/limit on joint1 (green rod to red box pivot), but other than that, it seems to work okay.  *shrug*  Use #9 for Cannon version.  Oimo demos http://www.babylonjs-playground.com/#IBGBX#1 and  http://www.babylonjs-playground.com/#3TNP9#3 are working, too.  It's not exactly dead.   :)

Thanks again for info.

Link to comment
Share on other sites

@Wingnut - I totally get what you're saying and love your "#10" PG scene. Did you create this from scratch? It's impressive either way in my opinion. And Oimo might "appear" to work on some level, I'm not able to use it in production under any circumstances currently - which is quite unfortunate and hope it can be salvaged in the near future - but it cost me allot of time already. Having said this, I certainly can't complain - not really - as I wasn't the person or people who spent countless hours building a great physics engine; and one that is simply given to use for free.:) So my respect to the authors  - regardless - and can only hope that it can be "fixed", or if it happens to be a version compatability issue with WebGL and/or BJS, then again I hope it can be solved in the near future; as I previously mentioned that having multiple choices for any toolset / extension in WebGL is invaluable to us all.

@jerome - I didn't mean to imply that SPS would become a physics system, however, once I saw the flocking PG scene using SPS, the bell went off in my head to make use of SPS in place of particle simulations for many physics simulations - which particles simply won't perform in the same way or can even achieve. So as you have commented that you will be expanding on SPS, I simply see the immense posibilities of more complex "actions" based upon mesh intersections and/or proximity. All I have to say is that just experimenting with what you've already built has been a fun experience, and any expansion of features in SPS is something I look forward to following, testing, and I'm certain using in production.

Cheers,

DB

Link to comment
Share on other sites

hi guys, I'm back

Well, this will be documented soon and some examples up to come but for now here's the way to use the brand new SPS feature : particle intersections !

You need first to activate this feature explicitly when creating your SPS (not enabled by default because it uses more memory and more RAM) with the optional parameter particleIntersection :

var sps = new SolidParticleSystem("sps", scene, {particleIntersection: true});

This is a method ot the class SolidParticle called, for consistency reasons : intersectsMesh()

 intersectsMesh(<SolidParticle | AbstractMesh> target)

 

For instance, in your SPS.updateParticle(particle) function, just do :

if ( particle.intersectsMesh(otherParticle) ) { // do fantastic stuff }

You can test this intersection with the same call also against any BJS standard mesh :

if ( particle.intersectsMesh(anyMesh) ) { // do fantastic stuff }

Note well that, for performance reasons, the intersection test is always done with an AABB computation, what is also known as the un-precise intersection mode in BJS (default mode).

Note that you can also check this intersection against a solid particle from any mesh :

if ( someMesh.intersectsMesh(anySolidParticle) ) { // do fantastic stuff }

As the method intersectsMesh() of the AbstractMesh class allows to force the precise mode, you can call always call it for mesh against particle intersection computation :

if ( someMesh.intersectsMesh(anySolidParticle, true) ) { // do fantastic stuff }

but just remember in this very case that it will have a significant computation cost and that this will only do half the job : precise mesh against un-precise particle (OOBB vs AABB)

So unless you have a very specific need, it's not recommended to use the mesh intersection precise mode with solid particles in general.

 

Final note : this works with any type of solid particles, even the ones automatically generated when you digest a mesh (sps.digest(mesh))

[EDIT] SPS doc updated in the Overviews section

Link to comment
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...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...