Monday, 22 October 2012
Under Construction
After taking a couple of months out to play Pioneer, to work out what to do next - then a couple of months to figure out how to do it... I've finally moved back into development. As usual Life Got In The Way, which it has a habit of doing and overall I've taken close to a years break between sprints.
I've taken a little time out to rework the renderer a bit, I've gone for soft shadows which really helps ground the scene and make it look a lot more solid. The look and feel here is key, and while I'm a long way off I think shadows were a nice distraction to have worked on. There are a few other graphics and rendering tasks on the list, but they might be backshelved for a while if I move into serious development.
Viewing the work of LEGO artists and communities on-line has really helped define the first goal of Pioneer Development - Sharing models and scenes. While there are a number of pre-rendered LEGO images that artists have made, I've not seen much real-time LEGO building, and I think the Pioneer environment would be great to help people share their MOCs if they don't have access to CG rendering or CAD.
Pioneer should be about sharing images, models, scenes or worlds. Its about Playing Well, and Playing Together. I want to be able to share what I've built and see what other people are building. This is about social building, and brickmanship.
I also want to be able to view historical sets, particularly the out of production iconic sets like Classic Space that helped build the LEGO brand over all these years. This is a celebration of everything they have done, and my homage to them. I'm not sure how this is going to play out, it might be I make a gallery of images, or of models to view. I'm avoiding all modern sets, all recent copyrights, brands and licencee material and anything that overlaps the LEGO company, their business model, their on-line presence and their console games.
Lastly, I've got my eye on building a world that Minifigs can explore. A dynamic, changing world made of colourful bricks. This is a log term concept for the project, and goes above and beyond anything I've got planned. But I'm aware that building a castle, town or lunar-base for minifigs to inhabit - or for you to walk around among them - would be a lot of fun. I pioneered networked multi-player during early development and think there is some strength to the idea of collaborative play.
So, that's where I am, and what I've been thinking about. If you were part of the Pioneer Alpha program, thanks for playing. There will be a beta soon - I'm putting together an improved building UI based on feedback and incorporating a couple of other features that were requested.
Keep it square, and think inside the box!
Thursday, 29 December 2011
New Code
A dozen classes later and I've injected a mock into my rendering thread so I can interrupt draw calls and simulate almost the entire process. This basically makes everything up to the draw call unit testable and turns my code into the most complicated of bagatelle machines.
Network packet arrives in one end, bounces from pillar to post, draw call comes out the other end!
This brings me a little close to Alpha, but more in a holiday-spirit-playing-with-code sense than the typical slaving over a hot keyboard. As I don't get paid for developing Pioneer I've been putting it aside for my birthday and then Xmas and have only snatched a couple of half-days this month.
In general the classes are easier to work with, and places the last stepping stone before adding variable level of detail rendering modes and dynamic shadows. Its also a little faster/smoother when playing and has fixed a really obscure visibility bug that would sometimes leave you with an invisible brick.
The large benefits have been the removal of a cyclic dependency which has meant I can straighten the code out into a directed acyclic graph. All elementary stuff but removing this particular spanner from the works has been kind of a personal quest. The new object graph (and a couple of mocks) has meant I can easily increase the test coverage, which is the next thing I'm going to fiddle with because I was a bit lazy on that front in the last couple of sprints. I'm probably going to see what I can do about cutting those mock objects out of the test harness too, since they add a potential maintenance cost.
Monday, 28 November 2011
Code Mines
This is another no update blogpost, but a real update is getting closer. A previous code review left me pondering... What if I just did it right?
So I thought I'd practice what I preach and do all of those fancy things that smart programmers dao.
The Pioneer codebase has always been dominated by the Brick class which describes the size, shape, position and colour of a building brick, and the Chunk class which measures 16x16 studs, contains zero to many Bricks and is arranged spatially with other Chunks to form the World. Almost everything was either in one of those classes, or operated on them.
So the code was largely a bit of a lump. The Brick and Chunk classes became tightly coupled, with the World becoming a resource locator for chunks. A simple shared pointer made it far too easy to pass ChunkPtrs around and hold on to them even though - theoretically - they were short lifespan objects.
While I stuck to reasonable guidelines and practices, it became easy to add lazy features and it wasn't until I wanted to add mesh LoD and runtime LoD switching and discovered that it was a bit tricky. The possible solutions
- expose more members as public, either through access specifiers or get accessors.
- bundle more responsibility onto the already bloated Chunk class
- refactor so that the object graph makes the new feature easy to add.
Both of the least-effort solutions felt pretty bad, but it looked like it should be fairly easy to extract a responsibility FROM the chunk and isolate the rendering in a new object. Even if it was a RenderableChunk class, it could still steal all of the occlusion, rendering and become a container for that stuff where it should be easy to add that mesh LOD functionality too.
And so the project went through whatever the opposite of suffering is as I pruned back the almighty Chunk. It lost a lot of fat, it also became a Directed Acyclic Graph and I could strip out a now redundant cycle.
Compile times were a little slow so I retypedeffed my shared pointers to incomplete types and made all of their clients rely on the abstract interface instead of the implementation. This reduced the amount of include files getting chained together and allowed me to hack away in small, fast iterations.
The new acyclic object graph made the test suite simpler and much easier to expand to be more comprehensive. I was never satisfied with my test coverage and having that easy to improve is a load off. Its almost as if the "better" code was also easier to unit test. Astounding!
Programming can be a bit like a new LEGO build. You know what its supposed to be when its finished but you haven't got any instructions so you add and remove bricks, and each iteration will get you incrementally closer to your goal. One brick removed, two bricks added.
There will need to be more time at the keyboard before anything appears, but the last of the big changes has happened. From here it looks like I'll just be putting bricks back together. Maybe the odd one or two will be shifter, but I've solved the problem I wanted to solve and a few more to boot.
So I thought I'd practice what I preach and do all of those fancy things that smart programmers dao.
The Pioneer codebase has always been dominated by the Brick class which describes the size, shape, position and colour of a building brick, and the Chunk class which measures 16x16 studs, contains zero to many Bricks and is arranged spatially with other Chunks to form the World. Almost everything was either in one of those classes, or operated on them.
So the code was largely a bit of a lump. The Brick and Chunk classes became tightly coupled, with the World becoming a resource locator for chunks. A simple shared pointer made it far too easy to pass ChunkPtrs around and hold on to them even though - theoretically - they were short lifespan objects.
While I stuck to reasonable guidelines and practices, it became easy to add lazy features and it wasn't until I wanted to add mesh LoD and runtime LoD switching and discovered that it was a bit tricky. The possible solutions
- expose more members as public, either through access specifiers or get accessors.
- bundle more responsibility onto the already bloated Chunk class
- refactor so that the object graph makes the new feature easy to add.
Both of the least-effort solutions felt pretty bad, but it looked like it should be fairly easy to extract a responsibility FROM the chunk and isolate the rendering in a new object. Even if it was a RenderableChunk class, it could still steal all of the occlusion, rendering and become a container for that stuff where it should be easy to add that mesh LOD functionality too.
And so the project went through whatever the opposite of suffering is as I pruned back the almighty Chunk. It lost a lot of fat, it also became a Directed Acyclic Graph and I could strip out a now redundant cycle.
Compile times were a little slow so I retypedeffed my shared pointers to incomplete types and made all of their clients rely on the abstract interface instead of the implementation. This reduced the amount of include files getting chained together and allowed me to hack away in small, fast iterations.
The new acyclic object graph made the test suite simpler and much easier to expand to be more comprehensive. I was never satisfied with my test coverage and having that easy to improve is a load off. Its almost as if the "better" code was also easier to unit test. Astounding!
Programming can be a bit like a new LEGO build. You know what its supposed to be when its finished but you haven't got any instructions so you add and remove bricks, and each iteration will get you incrementally closer to your goal. One brick removed, two bricks added.
There will need to be more time at the keyboard before anything appears, but the last of the big changes has happened. From here it looks like I'll just be putting bricks back together. Maybe the odd one or two will be shifter, but I've solved the problem I wanted to solve and a few more to boot.
Monday, 15 August 2011
Code Quality
Tonight I discovered a class that doesn't do what it says on the tin, so didn't do what I expected it to do and had two responsibilities so boot. So its been split in two, and each half aptly named. In retrospect its a lot of typing and when you finally run the game its *exactly the same* but that's kind of the point of this kind of refactoring. Its made adding new stuff easier and what I've got is easier to read for future revisions.
The clean-up has exposed a juxtaposition of bad habits, itself a more interesting point than the code or class layout in question. The contents of the class was place holder and had been overlooked for quality because it was "only temporary". Another symptom of being left to rot was the suspicious 'todo' comment that had never been followed up.
The experience has highlighted a serious difference between a naive implementation and bad code. Knowing that I was writing an implementation that was going to be thrown away meant I'd turned a blind-eye to a poor choice of interface, and that's where the rot started.
The old lesson relearned... there is NO SUCH THING as throwaway code. As you write, you just don't know how many weeks, months, or years a temporary class is going to last. I could just have easily have looked at it, saw it was ugly and left it alone. Or compounded the problem by just hacking my new code in. But the clean-up has left me with more functionality, less code and more readable, intuitive classes with shallower inheritance.
Sunday, 14 August 2011
Sprint 17 Complete
It has the new pantones, a few new bricks and a couple of tweaks. The vertex and fragment shaders have been disabled for now but will be back in a future sprint soon. A lot of graphical tweaks are pencilled in for release 19, while I'm expecting to focus on core building and useability for 18.
Thursday, 11 August 2011
Vertex Shader. Yeaj!
Just the act of making a tasty tasty coffee was enough to stimulate the little grey cells. I had a play with vertex and fragment shaders recently but I was only really having a play in the 'play for fun' rather than nerdcore critical-path programming.
One of the shaders I wanted to write was to make my blocks look a little more like physical LEGO bricks. The LEGO company make the plastic construction toy that has been my inspiration and physical building materials have different properties to intangible polygons.
Simulating the look of a real world item with computer graphics is always a fungineering task, but I hit upon the technique I'm going to use to get that extra va va voom out of my graphics pipeline using a vertex shader in the base render pass instead of during post-process or using a second render pass and additional VBO set.
More news as it breaks!
p.s. You can support the LEGO company by buying sets, bricks, toys or apparel from their online or storefront retail outlets. I highly recommend basically everything they sell.
Sunday, 31 July 2011
Subscribe to:
Posts (Atom)