• Advertisement
Sign in to follow this  
  • entries
    16
  • comments
    42
  • views
    9528

About this blog

Damn kids, get off my lawn!

Entries in this blog

Torque Game Builder is proving a little easier than I'd expected (so far anyway), so I've got a playable version of Mr Wibbly ready. Unfortunately I only have a Windows version (building the Mac version keeps dying for some reason), which you can download from here (.zip, 1.65Mb). It is still missing the main menu/high-score entry states, but the gameplay is up and running.

There's also a new gameplay movie with titles (I really shouldn't be allowed to use Windows Movie Maker) which you can download from here (.wmv, .zip, 4.4Mb).

How to play:
* Use the left/right cursor keys to run to the left/right respectively.
* Press "a" to toggle audio on/off.
* Press "Escape" to quit the game.
- The switches are toggled from "up" to "down".
- Each time you flick a switch you get 1,000 points.
- Every 10,000 points you get an extra life.
- Every 15,000 points a new UFO appears.
- Every 50,000 points the shields regenerate.

I've been trying to make the game harder, but it should be playable. Any comments/suggestions/criticisms are welcome.

TGB Wibbly!

After having "real-life" get in the way for a few weeks (damn work), I've started work on the Torque Game Builder port of Mr Wibbly. I hope to have a playable demo ready by early next week, but in the mean-time here's a little video ('cause all the cool kids are doing it) demonstrating my current progress. It's in WMV format, about 480KB.



And yes, it'll be for both Windows and Mac. And yes, anyone who wants the source-code is welcome to it when it's done.
Thanks for all the positive comments on Mr Wibbly. I've "finished" the XNA code to Mr Wibbly (see previous post), and you can download it from here (80kb). It's even got some commenting [smile].

@ Rob Loach: I signed up on OpenXNA to post the project there, but haven't got the slightest clue how to upload the project/images. If you can send me a PM (or comment) on how to do it, or you're welcome to post it up yourself.

With the XNA version out of the way, it's time to start on the Torque Game Builder version. Hopefully that will be done in a couple of weeks.
In the interests of learning XNA, I decided to port my old B&W game (Mr Wibbly) from the original C#/MDX1.1 version. A few changes were made, the resolution is now much larger and easier to see, and I made the game wide-screen. Without further delay, some screens:

* Title screen:

* Early game shot:

* More advanced game shot:

* High-score entry:


The gameplay is similar to Space Invaders, except you can't shoot. You must run from side-to-side, toggling the switches (from up to down) while the UFO shoots at you and eats away your shields. You get 1000 points each time you successfully toggle a switch. Every 10,000 points you get an extra life; every 20,000 points an extra UFO appears; every 50,000 points your shields are re-generated.

The controls are just the left/right cursor keys to move Mr Wibbly. When entering your initials in the high-score table, you use the up/down cursor keys to change the letter, and press to progress to the next character ( takes you to the previous letter).

The full source and resources are available here (178Kb zip). I've still got a few tweaks to make to the code, and also more documentation to be added tomorrow. I'll upload the "final" source when it's done later this week, along with the original MDX1.1 version.

Hope someone looks at it/enjoys it.
It's been a while, which indicates how exciting my life is.

I finally went to my graduation on Saturday, which involved sitting on the stage for two hours watching 500+ students graduate while I waited for my turn. Thankfully that is the last graduation I'll attend, and the very last formal education I'll endure. I'd post photo's, but some of you may be planning on eating again someday.

It looks like I'll be heading to Canada for a research visit from October 1 through until the end of December. I've got the flights and everything sorted out, but am now waiting on the necessary visa.

After about 4 months off, I've finally started doing some research again. After my thesis was submitted, I was seriously pissed-off with camera control, and didn't want anything to do with it. I've had a few ideas for improvement, so I'll be looking into those while in Canada. I've had to post-pone my current work until I go, since I have to prepare a journal paper.


Screenshot of the test application

This is the test application I use for most of my work at improving my constraint-based camera system. Most of the numbers will make sense to people, but the crap on the top-right is strictly to do with the current camera setup.

The Height, Distance, Orientation values define how the camera should be positioned in relation to the target (it's a pyramid, just on a bad angle). These are the constraints. The *Weight values indicate how important the constraint is to be satisfied. This basically allows you to control how the camera moves to satisfy certain constraints. So a low orientation weight means the camera will maintain distance/height, but doesn't care so much about rotation. The FrameCoherence weight controls the overall motion (smoothness) of the camera.

The camera system works by searching a subset of the environment (as shown by DomainSize, Passes, and ScaleFactor). The constraint solver tries to find a camera position that best satisfies all of the constraints. Because not all constraints are weighted equally (and the target moves), the optimal camera position cannot be known before time. My PhD was mostly on a quick way to find the optimal (near-optimal, since my method is incomplete) position.

What is cool about the constraint-based camera systems is how easy they are to extend. To add occlusion avoidance, I just introduce a new constraint to avoid obstacles. This doesn't require any modification to the constraint solver. Since all constraints are weighted, you can control how the camera will move to avoid occlusions. A high weight will make the camera avoid occlusions quickly, a low weight will avoid them slowly. In my current implementation I can make the camera avoid occlusions differently depending on where the occlusion is. Not that you'd want to, but you can.

The more common requirement of the constraints is actually to do more with cinematography. It's a straightforward process to create a new constraint for cinematic camera angles (e.g. two-shot, over-the-shoulder, etc...). The constraints can be turned on/off in between frames to create scripted cinematics. This is one area where I'll be looking to make a few improvements soon.

I guess that's probably the most confusing description of how my camera system works. If anyone wants more info, I'd be happy to try to explain it better [smile].

Thanks.

Thanks to everyone for their suggestions to my previous post. I've now got Rise of Nations (PC), Advance Wars 2 (GBA), Final Fantasy Tactics (GBA), and Starcraft (PC) on order (it wasn't in stock). Now if I could just buy enough time to play them all.

I'm actually planning to shift the focus of my research from camera control (been doing it for 4 years, bored out of my nut) to RTS AI (or maybe planning in general). I haven't started reading much, but I thought it would be a good idea to see what games are out there, how they work, etc. before I start trying to work on the AI.

I can't believe how much information there is to remember in an RTS! I thought my head was going to explode when I went through the first tutorial in Rise of Nations. This brings me to my complaint about games: they're too bloody hard.

I don't mean hard from a strategic point-of-view, I mean from a memory point-of-view. Back in the old days (C64 era), characters could run-and-jump, and could be controlled with a joystick with one button. The capabilities of characters now are numerous, so providing the user with the ability to control the character necessitates complex controllers and control schemes. Now I need to remember obscure button combos and when to use them, execute them with impeccable timing, etc.

The problem I have with this is the amount of time I can dedicate to gaming. When I am working, I usually only manage spurts of about 1-2 hours/month at best, and often go 3-4 months without gaming at all. If I spend the requisite time learning the control scheme, odds are pretty good that I won't get a chance to play further until another month or so. By that time I've forgotten all the combos and usually start back at the beginning to go through the requisite tutorial sections. I've lost count of the number of times I've played the first parts of Wind Waker, Beyond Good & Evil, Halo, and basically every game in my library (although I don't like Halo, so that has long since been retired).

I guess I'm not the hardcore gamer I used to be (or think I am), and should restrict myself to games that have easier control schemes. Help may be at hand with the Wii, and I can only hope that it offers diversity (simple games for me, complex games for the hardcore gamers) that I'm after.
Has anyone got any personal recommendations for good RTS games? I'm looking for something with good AI, and preferably on the PC (although any system except PS2 is OK). The last RTS I played was the original WarCraft (and I was crap at it).

After quite a long break (since early March), I'm finally getting back into the nitty-gritty of camera control research (solver optimizations). I'm coding up the little test framework for it, and hope to some some very un-exciting screens shortly.
It's been a while. I had the poor fortune of getting the flu a few weeks back, which basically put me in bed and unable to program for a while. I got it at the Strung Out/Death By Stereo concert (which was awesome btw). That'll teach me for going out in public.

Not a huge amount has been happening, but I did get my official thesis results last week. I got a Rank 1 (no modifications, no revisions, no re-submission), which makes me very damn happy. Apparently not that many people from my uni get that, which makes it all the sweeter. With a bit of luck I'll be graduating in early August, which marks the end of formal education for me.

I recently picked up a license to Torque Game Builder, which has caused me to start designing many shitty 2D games. The first that I actually implemented (in C#, I'm still learning Torque) is Rings. It's meant to be a cross between Columns (or Squigz for the Amiga nuts) and space invaders. It sounded good in theory.





You move the spaceship in a circle around the rings using the left/right keys, and shoot a block using the space bar. When you shoot 3 of the same colour block in a row, they disappear shrinking the ring. Every 2 seconds a new block is added, making the ring larger. Once it gets to a certain size, the game is over. My hope was that it would prove addictive and enjoyable like Tetris, but it's not [depressed].

It proved reasonably fun and has some potential, but is a bitch to control. It needs to have the speed of movement/time of new blocks/etc. tweaked to make it better, but I don't know if it's worth the effort. If anyone is interested, the absolutely horrible source code is available (.zip, 65Kb). It's playable, but not really a game.

Untitled

For those keeping score, I didn't get the job at my University, despite having my supervisor on the selection committee. Since the selection process is now over, I can actually talk to my supervisor to arrange what I'm going to do in the future. We are supposed to have a meeting this week (I hope) to discuss it.

On to the development stuff....

The 'dream' game that I've been brainstorming with my friend lately is "Pantaloons: Weird Beards' Treasure". The following is some of the concept art and model tests for it (all drawing/textures by Chris).


Title screen.


Concept drawing for the two different types of pirates (there'll be maybe 2 more variations).


The 3D textured model in the DirectX model viewer. The model is 109 polygons, and was built using Cinema4D, textured using MS Paint.

The idea

Pantaloons is a third-person action/adventure game, with more focus on action than adventure. The battles will involve 200+ pirates at a given time, which is why the models are really low-poly (they're also a lot easier to model with limited skills). The main purpose (for me) is to stress test my camera system, making sure it handles large numbers of dynamic entities without crapping itself. It will also have to handle in-game cinematics on-the-fly.

The game world is segregated so that each 'adventure' takes place on a single island. The goal at the moment is to get a single island built and working, which in itself should provide 1-2 hours of play time. The game can then be extended by adding new adventures by creating new islands. That's the plan anyway.

There's not much more to the current game design than what I've provided, since Chris is busy with work, and I'm busy starting new projects and never finishing them. It's getting out of hand, I really need to dedicate myself to finishing (or abandoning) some of these projects.
Not much has been going on lately, but I keep getting the feeling that I should update this journal more often.

I'm still waiting on my thesis results (I've got the examiners reports, and I'm very happy), but I have to wait for them to pass through the University's bureaucracy before I can say much. I'm also still waiting on news of the job at the University. It's been nearly 4 months, and the selection process in still ongoing [headshake].

I've completely converted to C# now, and going back to C++ makes me feel all dirty. I'll still need to use it for various time comparisons with old code though. While coding the logging system of a new project, I noticed that there wasn't much info around for getting system information with C#. I've cobbled together most of what I needed (no real networking stuff), and thought I'd share in case someone else needs/wants it.


using System;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using Microsoft.Win32;


namespace SysInfo
{
public class SysInfo
{
#region Native Methods

[StructLayout(LayoutKind.Sequential)]
public struct MemoryStatus
{
public uint dwLength;
public uint dwMemoryLoad;
public uint dwTotalPhys;
public uint dwAvailPhys;
public uint dwTotalPageFile;
public uint dwAvailPageFile;
public uint dwTotalVirtual;
public uint dwAvailVirtual;
}
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern void GlobalMemoryStatus(ref MemoryStatus ms);

#endregion

public struct ProcessorInfo
{
public string ProcessorName;
public string ProcessorDescription;
public int ProcessorSpeed;
}

#region Members

private MemoryStatus ms = new MemoryStatus();
private ProcessorInfo[] processorinfo;
private DriveInfo[] driveinfo;

#endregion

#region Properties

public string OperatingSystem
{
get { return System.Environment.OSVersion.VersionString; }
}
public string ServicePack
{
get { return System.Environment.OSVersion.ServicePack; }
}
public Version OperatingSystemVersion
{
get { return System.Environment.OSVersion.Version; }
}
public Version CLRVersion
{
get { return System.Environment.Version; }
}

public string SystemDirectory
{
get { return System.Environment.SystemDirectory; }
}
public string CurrentDirectory
{
get { return System.Environment.CurrentDirectory; }
}

public string UserName
{
get { return System.Environment.UserName; }
}
public string UserDomainName
{
get { return System.Environment.UserDomainName; }
}
public string NetBIOSName
{
get { return System.Environment.MachineName; }
}

public long WorkingSet
{
get { return System.Environment.WorkingSet; }
}
public int NumberOfProcessors
{
get { return System.Environment.ProcessorCount; }
}

public ProcessorInfo[] ProcessorInformation
{
get { return processorinfo; }
}

public long TotalPhysicalMemory
{
get { return ms.dwTotalPhys; }
}
public long TotalVirtualMemory
{
get { return ms.dwTotalVirtual; }
}
public long TotalPageFile
{
get { return ms.dwTotalPageFile; }
}
public long AvailablePhysicalMemory
{
get { return ms.dwAvailPhys; }
}
public long AvailableVirtualMemory
{
get { return ms.dwAvailVirtual; }
}
public long AvailablePageFile
{
get { return ms.dwAvailPageFile; }
}
public long PercentageAvailableMemory
{
get { return ms.dwMemoryLoad; }
}

public DriveInfo[] DriveInformation
{
get { return driveinfo; }
}

public string HostName
{
get { return Dns.GetHostName();}
}
public string HostIPAddress
{
get { return Dns.GetHostAddresses(Dns.GetHostName())[0].ToString(); }
}

#endregion

#region Methods

public SysInfo()
{
GlobalMemoryStatus(ref ms);

processorinfo = new ProcessorInfo[System.Environment.ProcessorCount];
for (int i = 0; i < System.Environment.ProcessorCount; i++)
{
string sKeyPath = @"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\SYSTEM\CentralProcessor\" + i;
processorinfo.ProcessorName = ReadRegistryObject(sKeyPath, "ProcessorNameString").ToString();
processorinfo.ProcessorDescription = ReadRegistryObject(sKeyPath, "Identifier").ToString();
processorinfo.ProcessorSpeed = (int)ReadRegistryObject(sKeyPath, "~MHz");
}

driveinfo = DriveInfo.GetDrives();
}

public void QueryStatus()
{
GlobalMemoryStatus(ref ms);
driveinfo = DriveInfo.GetDrives();
}

private object ReadRegistryObject(string sKeyPath, string sKey)
{
object o = Registry.GetValue(sKeyPath, sKey, null);
return o;
}

#endregion
}
}



A demo project can be downloaded from here.



I do have a new project in the works, but unfortunately it doesn't fit in with the 4E contest (why couldn't the elements include bad 80's TV shows, programmer art, and system crashing bugs?). I'll post some 'concept art' from this project soon.
Quote:

Could you get some type of gameplay using that model?


I'm not entirely sure I understand what you mean.

I managed to spend a bit of time today fixing some of the bugs in the code. In particular the aspect ratio bug (thanks for the heads-up). Here's some revised pics:




The code is now usable (running/jumping), meaning that I can test and debug the camera control methods as I please. Since I already have 3 different methods implemented, I'll crack open Texniccenter tomorrow to start writing the article. I've re-arranged the topics in the article differently from my earlier post, now they are in a format that should be easier to digest.

I plan to switch between implementing a new camera method, and writing it up. This way the article and code are updated regularly, and together. The current list of autonomous camera methods I plan on implementing/have implemented are:
1. Projection [done].
2. Polar coordinates [done].
3. Spherical coordinates [done].
4. Quaternion interpolation.
5. Proportional controllers.
6. Steering behaviours.
7. The constraint-based method developed for my PhD (hopefully my thesis results will come back before I release the code to this one though).

I will write up some other methods in the article, but won't implement them. Mostly because they're unlikely to be of much use to game developers. Once these methods are done, I'll move on to the replay/cinematography camera methods, which is the topic of the second of my 2 camera control articles. I'm not sure if I'll use the same framework for these, or whether I'll strip it down to the bare essentials (ditching PhysX), or move to C# and MDX. Either way, there will be fewer camera methods available for replays/cinematography than for gameplay.

The current build doesn't have occlusion avoidance, despite it now being an option (see pics). I plan on adding this code once all of the camera methods are done. Since I plan on writing this up after I finish implementation of the gameplay cameras, if anyone is really hanging out for the occlusion stuff, I can put it at the top of the list of things to do.

For the eager people wanting to look at the code, the current source and documentation can be downloaded from here (zip) at 3.3Mb. This zip contains all of the "art" (and I use the term loosely) assets as well as the code. It's a Visual Studio 2005 project, using Feb 2006 DX and PhysX 2.3.3. I have my doubts that any of you will get it to compile, but good luck [smile].

EDIT: Just uploaded the executable at ~200Kb. You'll need to download the exe and the source, and put the exe in the same folder as the PhysX dll's. Lot's of messing about, I'll fix it for next time.

The controls are: up/down/left/right cursor keys control the movement of the model, space for jump. For the free-roaming camera, the WASD keys handle movement, while the mouse handles 'looking'.

Remember, the code is to demonstrate camera control not engine design (and is free), so please refrain from "this code sucks" comments. Other comments are welcome.
Quite some time since I updated this. I've been spending a ton of time working on job interviews and such, so haven't done too much development or writing.

In aid of my article on third-person camera control (see earlier entries), I've decided to hack together some sample code. This code basically allows on-the-fly switching of any third-person camera method. I've currently got free-roaming, coordinate transformation, polar coordinates, and spherical coordinates working. I'll have more once I finish all of the 'framework' coding.

Without further delay, feast your eyes of dodgy programming and programmer art:

camera01
camera02
camera03
camera04

It's written in C++ (Visual Studio 2005), DirectX (Feb 2006), and uses PhysX 2.3.3. I've still got to clean-up a lot of code, in particular the player controller. Once that's done I can start focusing on the camera systems and writing.

I'm hoping to have the first part of the article (on player control and the three simple camera methods I have at the moment), and the source available in a week or so. It all depends on how much more I have to fight with PhysX.
After spending the best part of the week slacking off and building furniture, it's back to work.

As promised, the general outline for the camera control article is as follows (slightly modified from my thesis):

Article/Section 1 - Camera Control Techniques
This article basically describes the different techniques that have been applied to controlling the position/motion of virtual camera systems.

  • Coordinate Transformation.
  • Polar Coordinates.
  • Spherical Coordinates.
  • Applying spring systems to improve camera motion with polar/spherical coordinates.
  • Quaternion Interpolation.
  • Steering.
  • Proportional Controllers.
  • Potential Fields.
  • Path Planning and Spline systems.
  • Image-based Visual Servoing.
  • Constraint Satisfaction Methods. (This was the focus of my thesis, so it is more detailed than some of the previous methods).


Article/Section 2 - Cinematography and Replay Camera Systems
This article covers the 'higher-level' concepts involved in cinematography and replay systems. I don't personally find either of these interesting, so the theory won't be overly detailed (sufficient though).

  • Formal Languages and Path Planning.
  • State-based Cinematography.
  • Agents and Intelligent Assistants.
  • Constraint-based Cinematography.
  • Knowledge-based Cinematography.


Article/Section 3 - Occlusion Detection and Avoidance Systems
This article covers the different methods for detecting and avoiding occlusion. The methods can be mixed-and-matched quite a bit.

Occlusion Detection Methods (some of these have sub-categories):

  • Ray-casting Methods.
  • Bounding Volume Casting.
  • Overlapping Bounding Volumes.
  • Examining Image Composition (hemicubes, shadowing, etc.).


Occlusion Avoidance Methods:

  • Default Movement on Occlusion.
  • Movement based on ray-intersection.
  • Movement based on image composition.
  • Path Finding (including the 'bread-crumbing' approach).
  • Potential Fields.
  • Cheating: Occluder Manipulation (making occluders transparent, moving them, etc.).



There are different control techniques that can be discussed as well, but I'm not sure which article to attach them to. There are also a lot of specific problems that are associated with occlusion that I haven't listed here, but will be covered.

Any feedback on techniques you think are missing (I'm sure there will be some) is welcomed.


In other news, I've got a phone interview on Friday morning for a job at my University (lectureship). Getting a job in the real-world still frightens me. I'll be preparing different materials for that interview all week, so I won't make any headway into the camera control article until at least next week.

Last Friday I received the 3 books I was waiting on. I have almost finished reading Programming C# (excellent book, thanks for the heads-up). Once I feel a bit more comfortable with C#, I'll attack Game Engine Toolset Development. The other book was my 2 copies of AI Game Programming Wisdom 3 (2 copies since I'm an author). I've had a quick flick through some of the articles, and there seems to be a lot there that interests me.

I did complete "Mr Wibbly", but after reading the book on C#, I realized just how badly I had programmed it. I won't be releasing the source/binary unless anyone is really interested.
Greetings again.

I'm still waiting for my C# books to arrive, but decided to forge ahead and start coding anyway. The result is a remake of the first part of the classic Amiga game "Mr Wobbly Leg and the Invaders from Space". I'm sure you're all familiar with it [smile]. Unfortunately my friend and I couldn't quite remember how the game worked, so I ended up coding a bastardized version of it. I present to you:

Mr Wibbly vs. The Invaders From Neptune 12 1/2

Main Menu:
Mr Wibbly Menu

Gameplay:
Mr Wibbly Gameplay

I haven't quite finished it off (high-score table isn't working, no audio), but I'll post the binary/source in a few days if I get around to finishing it. The most important thing is that I learned a great deal.


In response to my first post (below):

@Anonymous Poster: Sorry, I don't have any video's from my research.

@superpig: There are two issues that I have with hosting my thesis on GD. (1) There are some things in there that I don't really want the public to see, and hosting it on a popular site like GD isn't the best way to accomplish that. (2) A thesis probably isn't the best way for people to learn about some techniques. I can't speak for all theses, but mine contains a lot of extra stuff about motivations, research contributions, goals of the research, etc. that aren't necessary to learning about certain techniques.

I would like to publish something from my research on GD though, as what's the point of research if nobody gets to see/use/learn from it?

My supervisor asked me to prepare a journal paper based on my Survey of camera control methods. If it suits you, I can adapt this chapter of my thesis (currently at about 40-something pages) for publication here. It basically details:
* the various camera control methods (polar/spherical coordinates, quaternion interpolation, spline systems, path finding, potential fields, a few others);
* an introduction to Cinematography and Replay concepts, the different autonomous cinematography systems (formal languages, etc.);
* the different methods for detecting occlusion in a virtual environment (ray-casting, bounding-volume casting, hemicubes, etc.);
* how to use this occlusion information to make the camera avoid it (potential fields, constraints, etc.); and
* a brief look at the different control issues that are encountered when using autonomous camera systems.

If this is something that you'd like to host, then I am more than happy to adapt my chapter/journal paper to suit the target audience. Let me know what you guys think.

Anyway, that's enough ranting for today.
Greetings all!

I signed up to GDNet+ a while back, but didn't want to start a journal until I had something to talk about. I still don't have anything to talk about, but I figured I'd start a journal anyway.

A little about me:

My name is Owen Bourne, and I'm a 27 year old male from the Gold Coast in Australia. I have just finished my PhD (thesis is submitted, waiting for results) titled "Constraint-Based Intelligent Camera Control for Interactive Digital Entertainment". I basically looked at a lot of different representations for autonomously controlling a camera in a 3D world, primarily 3rd-person games like Super Mario Sunshine. My representation allows for some pretty advanced features, and can do cinematography (or any other rules you might want to implement) in real-time. Since it is not everyone's cup-of-tea, I won't go into much detail about my system unless anyone is really interested.

So now that I have finished my PhD, I've been confronted with what to do now. I don't really want to continue researching camera control, since after 4 years I think I might go insane if I continue down that path. I'm currently weighing up various future research options, but have yet to find anything that really grabs me. I'm still planning on researching game AI though. Any suggestions for projects would be welcomed.

My current project to kill some time (until my thesis results are in) is to construct a really badly designed and implemented game engine in C# and Managed DirectX. As a seasoned C++/OpenGL programmer, I figure it is unlikely that I'll be able to learn C#, DirectX, AND create a good game engine on my first attempt. Therefore, I'm aiming to get something working and learn by failure. Hopefully after 10-20 attempts, I might get something decent going. If anyone knows of a good C# book, I'd love any recommendations (I already plan on getting Game Engine Toolset Development).

I'm not really too sure what I plan to post here, but probably it'll be more about research than game development. I think that's enough rambling for today.
Sign in to follow this  
  • Advertisement