Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
Offline mc-kay  
#1 Posted : Monday, November 28, 2011 10:55:29 PM(UTC)
mc-kay

Medals: Admin

Joined: 8/24/2011(UTC)
Posts: 138
Location: Hannover

Thanks: 1 times
Was thanked: 12 time(s) in 7 post(s)
Is there a camera for the 2D mode available?
Lets say I have a object that will be rendered at Point(2f, 0.5f), what have I to do to view it?

Wanna join the discussion?! Login to your forum accountregister a new account. Or Connect via Facebook Twitter Google

Offline Benjamin  
#2 Posted : Tuesday, November 29, 2011 3:01:13 AM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Not really, you could build one very easily. All you have to do is to manipulate the ScreenArea.ViewProjection2D Matrix.

In order to see outside of the 0-1 range you should also disable the optimizations in the Draw methods of Material2D and derived classes.

I recommend staying in relative space however, you can have your world objects in whatever range (100.0, 53.7), just use a 2D Camera offset (-100, -53.2) to see objects in local space (resulting in 0, 0.5), then all optimizations can stay as they are and you can render tons of 2d objects. Even better would be some kind of optimization to not render your whole 2D level, but only stuff that is in range via your game code.
Offline s990we  
#3 Posted : Saturday, February 18, 2012 4:09:43 PM(UTC)
s990we

Joined: 8/24/2011(UTC)
Posts: 7

Originally Posted by: Benjamin Nitschke (DeltaEngine) Go to Quoted Post
Not really, you could build one very easily. All you have to do is to manipulate the ScreenArea.ViewProjection2D Matrix.

In order to see outside of the 0-1 range you should also disable the optimizations in the Draw methods of Material2D and derived classes.

I recommend staying in relative space however, you can have your world objects in whatever range (100.0, 53.7), just use a 2D Camera offset (-100, -53.2) to see objects in local space (resulting in 0, 0.5), then all optimizations can stay as they are and you can render tons of 2d objects. Even better would be some kind of optimization to not render your whole 2D level, but only stuff that is in range via your game code.


Is there any plans to add a 2d camera?
If not, can you explain how I can create a camera that can zoom/rotate/move for a 2d game?
Offline elasto  
#4 Posted : Saturday, February 18, 2012 4:59:02 PM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Doh! There's a ScreenArea.ViewProjection2D Matrix? That explains a lot!

The only problem with DeltaEngine is that you don't know what you don't know about it!

I've written a 2D camera class that scrolls and zooms nicely - and has somewhat 'snazzy' features like it initialising to a zoom level that shows the whole world and it never letting you zoom or drag yourself outside of the world.

HOWEVER! I didn't know about ScreenArea.ViewProjection2D so I couldn't let classes like Effect know I'd moved my local viewpoint (so I couldn't use them)

SO! It's gonna need a bit of a rewrite - but once I've finished I don't mind donating it to the DE codebase.

EXCEPT! I'm gonna have to brush up on DE's exacting standards for code formatting before I can do that! :) Not particularly fair to make them refactor all my code :p
Offline s990we  
#5 Posted : Saturday, February 18, 2012 5:29:28 PM(UTC)
s990we

Joined: 8/24/2011(UTC)
Posts: 7

Originally Posted by: PG Go to Quoted Post
Doh! There's a ScreenArea.ViewProjection2D Matrix? That explains a lot!

The only problem with DeltaEngine is that you don't know what you don't know about it!

I've written a 2D camera class that scrolls and zooms nicely - and has somewhat 'snazzy' features like it initialising to a zoom level that shows the whole world and it never letting you zoom or drag yourself outside of the world.

HOWEVER! I didn't know about ScreenArea.ViewProjection2D so I couldn't let classes like Effect know I'd moved my local viewpoint (so I couldn't use them)

SO! It's gonna need a bit of a rewrite - but once I've finished I don't mind donating it to the DE codebase.

EXCEPT! I'm gonna have to brush up on DE's exacting standards for code formatting before I can do that! :) Not particularly fair to make them refactor all my code :p


One limitation of changing ScreenArea.ViewProjection2D is that everything that is outside the [0,0]-[1,1] will not be drawn.

How does your current camera work? (Could you post/send it to me?)
Offline elasto  
#6 Posted : Saturday, February 18, 2012 5:50:14 PM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Originally Posted by: s990we Go to Quoted Post
One limitation of changing ScreenArea.ViewProjection2D is that everything that is outside the [0,0]-[1,1] will not be drawn.

How does your current camera work? (Could you post/send it to me?)
There's not really much point sending it as it's so bespoke right now. It has its own coordinate systems built in that'd be somewhat incomprehensible to anyone but me :)

Essentially it translates objects from world coordinates to screen coordinates and anything that ends up inside of [0,0]-[1,1] gets drawn.

I'd rather look into what's available before sharing any code with anyone cos I'm clearly not taking important shortcuts that I could. Plus my camera has a critical limitation in that it can't use the Effect class (so I had to roll my own).

Edited by user Saturday, February 18, 2012 5:51:04 PM(UTC)  | Reason: Not specified

Offline bfox  
#7 Posted : Saturday, February 18, 2012 6:50:09 PM(UTC)
bfox

Joined: 8/22/2011(UTC)
Posts: 170
Location: Moscow

Thanks: 3 times
Was thanked: 2 time(s) in 2 post(s)
a little bit of my code Smile
Code:
public class Camera2D : BaseCamera

Code:
        public Camera2D(Vector setPosition)
            : base(setPosition)
        {
            lookDirection = -Vector.UnitZ;
            UpDirection = Vector.UnitY;
            RighDefenseGameirection = Vector.UnitX;
            NearPlane = 1f;
            FarPlane = 15f;
            FieldOfView = MathHelper.DegreeToRadians(90);
        }

Code:
      
 public Vector RayFromWorldToScreen(Point input)
        {
            return ScreenSpace.Project(new Vector(input.X, input.Y, 0));
        }

and
Code:
        public virtual void Draw()
        {
            BillboardManager.Instance.Draw(Material, Posistion, Size, Angle);
        }


Code:
                material.billboardMode = BillboardMode.Ground;
                material.DrawLayer = RenderLayer.Normal;

and angle = -90;

Edited by user Saturday, February 18, 2012 6:52:44 PM(UTC)  | Reason: Not specified

Russian game developer.
Давайте делать игры в команде. Идет набор.
Offline Benjamin  
#8 Posted : Monday, February 20, 2012 3:50:15 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Exciting stuff, interesting to see that everyone finds different solutions. We will try out what works best in v0.9.5 and see how it can be improved along with some other needed things (like DepthBuffer drawing for 2D).
Offline Nick  
#9 Posted : Tuesday, April 3, 2012 1:59:59 AM(UTC)
Nick

Joined: 3/14/2012(UTC)
Posts: 19

Hi,

I would vote for the 2dCamera as a very important feature too. I guess that would help any
kind of 2D editor to zoom and pan its content. Benjamin, you mentioned that it'll be part of 9.5?
Is it postponed? If so, has anyone accomplished to implement something so far and would be so kind to to share?

Regards

Offline Benjamin  
#10 Posted : Tuesday, April 3, 2012 2:20:41 AM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Yes the feature is still in v0.9.5, but not done yet .. I have seen different solutions, maybe the Soulcraft Worldmap comes closest (it renderes a 3D scene with a simple camera and it all looks very 2D, but allows zooming, effects, etc. very easily). I have not done much rendering myself in the past months, but many other people have probably written something useful .. now the hard part is getting them to share their code Blink
Offline elasto  
#11 Posted : Tuesday, April 3, 2012 2:32:04 AM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Bah. My code is just so bespoke... I'll even be amending the Delta.Rendering.Effects class to fit in with how I coded it now the source code to that is available.

I'm really happy with it but the way I've done it is really not a good way for anyone else to do it :p

(Plus I've read through the list of requirements for submitting code into DE - demands on how to structure the code and such - and it's just plain scary!)
Offline Benjamin  
#12 Posted : Tuesday, April 3, 2012 2:42:03 AM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
I guess now that I am pretty much developing myself and letting the community help I am less strict than before. The basis is also very solid (very rarely bugs are found in lower classes).

PG: Would love if you would contribute some useful code via an extra fork on codeplex, don't worry about style, etc. :)
Internetfreak is also now pushing code to the Tools fork, so things are going well.

I will only merge code after I have fixed it up and tested it anyway, but if code is in some extra branch/fork it is already useful to other members.

PS: What do you guys thing about supporting GitHub as well (for the forks)? I did not really like Git itself in the past, but the GitHub website is getting better and better for sharing and collaboration and others (like CodePlex) are not really catching up.
Offline Nick  
#13 Posted : Tuesday, April 3, 2012 2:58:05 AM(UTC)
Nick

Joined: 3/14/2012(UTC)
Posts: 19

Oh, 3D i see. More to look into. Smile
And by the way thanks for updating the tool\editor stuff so quickly. Great help.

Offline elasto  
#14 Posted : Tuesday, April 3, 2012 3:15:34 AM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Originally Posted by: Benjamin Nitschke (DeltaEngine) Go to Quoted Post
PG: Would love if you would contribute some useful code via an extra fork on codeplex, don't worry about style, etc. :)
Bah, it's very kind of you to say, but, seriously, it's really very bespoke right now! As a trivial example, it's all based on Vectors not Points - with X, Y and Z all shifting the location of the 2D tile; It's got numerous Draw method overloads that do different things; and the methodology I've used for controlling zoom and such will surely be totally incomprehensible! (I've got kinda two zooms - one for the actual map, and one for animating it as my UI expands from the edges. And the worst part, as I've mentioned before, is that Effects don't work with it.

I fear I really must pass for now! :)
Offline elasto  
#15 Posted : Thursday, April 5, 2012 2:35:46 AM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Ok ok... :)

When I've got a moment, what I'll do is copy my Camera class and remove some of the extraneous features (like the pseudo-3D stuff) and then add in a feature or two like rotation (which I haven't needed to date). Then, once I've been able to test the whole thing on my iPad I'll comment it better and upload the class in this thread or into a fork.

Then someone can go through my code and show me how I should have done it!

Really struggling for time right now though. I'm home alone with two children (aged 2-4yo) and concentrating on anything at all, even my own games, is damn near impossible most of the time...
Offline elasto  
#16 Posted : Wednesday, May 9, 2012 9:06:55 AM(UTC)
elasto

Joined: 8/23/2011(UTC)
Posts: 245

Thanks: 6 times
Was thanked: 12 time(s) in 11 post(s)
Ok, so this is actually a whole new camera class from what I had a month ago. I decided what I had then, though it worked, was done in far too complicated a way so just wrote it again.

It's important to note that it still doesn't dovetail with DE's rendering very well in that, for example, you'd have to amend the DE Effect class to call into here to do its drawing so that any camera movement will be correctly respected.

Also it's important to note that I have edited this code in this post because I use my own DrawManager class that incorporates RenderLayers. eg Where the code says Rect.DrawFilled(...) I have my own class and method Drawing.DrawFilledRectangle(...) - and I may have made a mistake. Just bear in mind these lines of code are untested!

Code:
using Delta.ContentSystem.Rendering;
using Delta.Engine;
using Delta.Rendering.Basics.Drawing;
using Delta.Rendering.Basics.Materials;
using Delta.Utilities.Datatypes;
using Delta.Utilities.Datatypes.Advanced;

using System;

namespace X
{
    internal static class Camera
    {
        // Used to help determine if the user has attempted to move the camera outside of the world
        private static float WorldAspectRatio { get; set; }

        // LetterBox is the viewport onto the world. It represents the section of the screen that is drawn on. 
        // As such it can be smaller than ScreenSpace.DrawArea (but should not go outside of it)
        // eg. if ScreenSpace.Draw area is a Rectangle from (.1,.1)->(.9,.9) and LetterBox is (.1,.1)->(.5,.9) then 
        //     the camera does not draw on the right hand side from (.5,.1) to (.9,.9).
        private static Rectangle LetterBox { get; set; }

        // If LetterBox is not the same size as ScreenSpace.DrawArea then these four Rectangles represent the sections of screen not drawn on
        // This if for drawing a coloured backdrop for UI elements etc.
        private static Rectangle FrameTop { get; set; }
        private static Rectangle FrameLeft { get; set; }
        private static Rectangle FrameRight { get; set; }
        private static Rectangle FrameBottom { get; set; }

        // This variable records the amount the camera has panned
        private static Point Offset { get; set; }

        // This variable represents the amount of zoom that has been applied
        private static float Zoom { get; set; }

        // This is how much zoom occurs per 'tick' of zoom - eg per tick of mousewheel
        private const float ZoomIncrement = .975f;

        #region Init

        /// <summary>
        /// This should always be called prior to using the camera or on any aspect change
        /// </summary>
        internal static void Init(float worldAspectRatio, Rectangle letterBox)
        {
            WorldAspectRatio = worldAspectRatio;
            LetterBox = letterBox;
            var drawArea = ScreenSpace.DrawArea;
            FrameTop = new Rectangle(drawArea.TopLeft, new Size(drawArea.Width, LetterBox.Top - drawArea.Top));
            FrameLeft = new Rectangle(new Point(drawArea.Left, LetterBox.Top), new Size(LetterBox.Left - drawArea.Left, LetterBox.Height));
            FrameRight = new Rectangle(LetterBox.TopRight, new Size(drawArea.Right - LetterBox.Right, LetterBox.Height));
            FrameBottom = new Rectangle(new Point(drawArea.Left, LetterBox.Bottom), new Size(drawArea.Width, drawArea.Bottom - LetterBox.Bottom));
            Offset = Point.Zero;
            Zoom = 1;
        }


        /// <summary>
        /// This draws the frame around the letterbox
        /// </summary>
        internal static void DrawFrame(Color color)
        {
            Rect.DrawFilled(FrameTop, color);
            Rect.DrawFilled(FrameLeft, color);
            Rect.DrawFilled(FrameRight, color);
            Rect.DrawFilled(FrameBottom, color);
        }

        #endregion

        #region Transformations

        /// <summary>
        /// Translates from quadratic screen coordinates (0,0)-(1,1) to world coordinates - taking into account the camera's zoom & movement 
        /// This might be used for, for example, finding the world coordinates of where the user clicked the mouse, in order to select an object
        /// </summary>
        internal static Point ScreenToWorld(Point point)
        {
            point /= Zoom;
            point += Offset;
            return point;
        }


        /// <summary>
        /// Translates from world coordinates to screen coordinates
        /// This will be used for, for example, drawing objects
        /// </summary>
        internal static Point WorldToScreen(Point point)
        {
            point -= Offset;
            point *= Zoom;
            return point;
        }

        #endregion

        #region Draw Primitives

        /// <summary>
        /// Clears the letterbox area of the screen, setting it to the required colour
        /// </summary>
        internal static void Clear(Color color)
        {
            Rect.DrawFilled(LetterBox, color);
        }

        /// <summary>
        /// Draws a filled rectangle at the required position, in the required colour
        /// </summary>
        internal static void DrawFilledRectangle(Rectangle worldDrawArea, Color color)
        {
            var drawArea = Rectangle.FromCorners(WorldToScreen(worldDrawArea.TopLeft), WorldToScreen(worldDrawArea.BottomRight));

            if (LetterBox.Contains(drawArea) == ContainmentType.None) return;

            Rect.DrawFilled(drawArea, color);
        }

        /// <summary>
        /// Draws an unfilled rectangle at the required position, in the required colour
        /// </summary>
        internal static void DrawRectangleOutline(Rectangle worldDrawArea, Color color)
        {
            var drawArea = Rectangle.FromCorners(WorldToScreen(worldDrawArea.TopLeft), WorldToScreen(worldDrawArea.BottomRight));

            if (LetterBox.Contains(drawArea) == ContainmentType.None) return;

            Rect.DrawFilled(drawArea, color, drawLayer);
        }

        /// <summary>
        /// Draws a filled circle at the required position, in the required colour
        /// </summary>
        internal static void DrawFilledCircle(Point center, float radius, Color color)
        {
            center = WorldToScreen(center);
            radius *= Zoom;

            if (center.X + radius < LetterBox.Left || center.X - radius > LetterBox.Right || center.Y - radius > LetterBox.Bottom || center.Y + radius < LetterBox.Top) return;

            Circle.DrawFilled(center, radius, color);
        }

        /// <summary>
        /// Draws an unfilled circle at the required position, in the required colour
        /// </summary>
        internal static void DrawCircleOutline(Point center, float radius, Color color)
        {
            center = WorldToScreen(center);
            radius *= Zoom;

            if (center.X + radius < LetterBox.Left || center.X - radius > LetterBox.Right || center.Y - radius > LetterBox.Bottom || center.Y + radius < LetterBox.Top) return;

            Circle.DrawOutline(center, radius, color);
        }

        /// <summary>
        /// Draws a line at the required position, in the required colour
        /// </summary>
        internal static void DrawLine(Point point1, Point point2, Color color)
        {
            point1 = WorldToScreen(point1);
            point2 = WorldToScreen(point2);

            var left = Math.Min(point1.X, point2.X);
            var right = Math.Max(point1.X, point2.X);
            var top = Math.Min(point1.Y, point2.Y);
            var bottom = Math.Max(point1.Y, point2.Y);

            if (right < LetterBox.Left || left > LetterBox.Right || top > LetterBox.Bottom || bottom < LetterBox.Top) return;

            Line.Draw(point1, point2, color);
        }

        #endregion

        #region Draw Material2D

        /// <summary>
        /// Draws an image at the required position, with the required rotation
        /// </summary>
        internal static void DrawImage(Material2D image, Rectangle worldDrawArea, float rotation = 0)
        {
            var drawArea = Rectangle.FromCorners(WorldToScreen(worldDrawArea.TopLeft), WorldToScreen(worldDrawArea.BottomRight));

            if (LetterBox.Contains(drawArea) == ContainmentType.None) return;

            image.Draw(drawArea, rotation);
        }

        #endregion

        #region Draw Material2DColored

        /// <summary>
        /// Draws an image but clips the UV coordinates to the letterbox 
        /// This should only be used for a backdrop image that fills the whole worldarea (else fix the uv coordinate calculation)
        /// </summary>
        internal static void DrawImageClipped(Material2DColored image, Rectangle worldDrawArea)
        {
            var drawArea = Rectangle.FromCorners(WorldToScreen(worldDrawArea.TopLeft), WorldToScreen(worldDrawArea.BottomRight));

            if (LetterBox.Contains(drawArea) == ContainmentType.None) return;

            float left = (LetterBox.Left - drawArea.Left) / drawArea.Width;
            float top = (LetterBox.Top - drawArea.Top) / drawArea.Height;
            float right = (LetterBox.Right - drawArea.Left) / drawArea.Width;
            float bottom = (LetterBox.Bottom - drawArea.Top) / drawArea.Height;

            left = image.UV.Left + image.UV.Width * left;
            top = image.UV.Top + image.UV.Height * top;
            right = image.UV.Left + image.UV.Width * right;
            bottom = image.UV.Top + image.UV.Height * bottom;

            image.Draw(LetterBox, new Rectangle(left, top, right - left, bottom - top));
        }

        /// <summary>
        /// Draws an image at the required position, with the required rotation, with the required alpha
        /// </summary>
        internal static void DrawImage(Material2DColored image, Rectangle worldDrawArea, float rotation = 0, float alpha = 1)
        {
            var drawArea = Rectangle.FromCorners(WorldToScreen(worldDrawArea.TopLeft), WorldToScreen(worldDrawArea.BottomRight));

            if (LetterBox.Contains(drawArea) == ContainmentType.None) return;

            image.BlendColor.A = alpha;
            image.Draw(drawArea, rotation);
        }

        /// <summary>
        /// Draws an image at the required position, with the required rotation, applying a blendcolor
        /// </summary>
        internal static void DrawImage(Material2DColored image, Rectangle worldDrawArea, Color blendColor, float rotation = 0)
        {
            var drawArea = Rectangle.FromCorners(WorldToScreen(worldDrawArea.TopLeft), WorldToScreen(worldDrawArea.BottomRight));

            if (LetterBox.Contains(drawArea) == ContainmentType.None) return;

            image.BlendColor = blendColor;
            image.Draw(drawArea, rotation);
        }

        #endregion

        #region Movement

        /// <summary>
        /// Zoom the camera viewpoint into or out of the world (eg responding to a mousewheel or finger pinch)
        /// FixViewpoint will attempt to pan the camera to keep the viewpoint inside the worldarea - and if it can't it will rollback the zoom
        /// </summary>
        /// <param name="ticks"></param>
        internal static void ApplyZoom(float ticks)
        {
            float validZoom = Zoom;
            Point validOffset = Offset;

            // When you zoom, you wish the center of the screen to remain pointed at the same spot in the world.
            // Hence a zoom also adjusts Offset
            Point center = ScreenToWorld(LetterBox.Center);
            Zoom *= (float)Math.Pow(ZoomIncrement, -ticks);
            Offset = center - LetterBox.Center / Zoom;

            //TODO: Instead, find closest valid zoom
            if (!FixViewpoint()) { Zoom = validZoom; Offset = validOffset; }
        }

        /// <summary>
        /// Pans the camera around the world (eg responding to a mousedrag or fingerdrag)
        /// FixViewpoint will re-pan the camera if this pan took the viewpoint outside of the world
        /// </summary>
        internal static void ApplyPan(Point point)
        {
            Point validOffset = Offset;
            Offset -= point / Zoom;

            //TODO: Instead, find closest valid translate
            if (!FixViewpoint()) Offset = validOffset;
        }

        /// <summary>
        /// Checks the viewpoint has not brought anything outside of the world inside the letterbox, and if so attempts to pan to shift it back out of view
        /// If it cannot find a way to pan it, it returns false
        /// </summary>
        /// <returns></returns>
        private static bool FixViewpoint()
        {
            var tl = ScreenToWorld(LetterBox.TopLeft);
            var offsetX1 = tl.X;
            if (offsetX1 > 0) offsetX1 = 0;

            var tr = ScreenToWorld(LetterBox.TopRight);
            var offsetX2 = tr.X - WorldAspectRatio - offsetX1;
            if (offsetX2 < 0) offsetX2 = 0;

            if (offsetX1 != 0 && offsetX2 != 0) return false;

            var offsetY1 = tl.Y;
            if (offsetY1 > 0) offsetY1 = 0;

            var bl = ScreenToWorld(LetterBox.BottomLeft);
            var offsetY2 = bl.Y - 1 - offsetY1;
            if (offsetY2 < 0) offsetY2 = 0;

            if (offsetY1 != 0 && offsetY2 != 0) return false;

            Offset -= new Point(offsetX1 + offsetX2, offsetY1 + offsetY2);
            return true;
        }

        #endregion
    }
}

Edited by user Wednesday, May 9, 2012 9:15:32 AM(UTC)  | Reason: Not specified

Offline Benjamin  
#17 Posted : Wednesday, May 9, 2012 12:19:46 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Looks cool, thanks for sharing. Will be included some day ^^
Rss Feed  Atom Feed
Users browsing this topic
Guest (2), OceanSpiders 2.0
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Powered by YAF.NET | YAF.NET © 2003-2023, Yet Another Forum.NET
This page was generated in 0.174 seconds.