Anyway, work on GTL3.0 continues at pace, well infact it started at pace and the pace has just letup because I'm starting to get tired, however it's been a pretty productive sunday [smile]
So, whats been done?
1) Main API
Most of the main API has been done, there are 5 loading functions which is an increase of the 3 standard functions in GTL2.x.
As before there is the standard load from a given file name function and a load from a filename as a certain type function. The custom loader function has had an overhall however and now comes in 3 types.
- custom loader with filename
- custom loader with filename and type id
- custom loader with type id
The loader function has also changed; instead of supplying a reader and seeker function the user now supplies a single function which is expected to read in all the data and return it when done.
Each of these functions can operate in Async mode (so the loaders MUST be reentrant!) but default to Sync mode (a define might well be able to change that in the near future however.
As mentioned in a previous post GTL now has an initalise function, this comes in two flavours;
The first, and probably most used, version simply takes the number of worker threads to spawn and the default origin for images (defaults, as with GTL, to top right as (0,0)).
The second version also takes a vector of user defined types. This vector contains a stucture which holds the extension for the file type and the decoder used to convert the data to a userable data format. The function then returns a map of to extensions to type ids, so for a given file extension you can extract the id GTL3 uses to select the decoder.
2) The decoders
In keeping with the changes to the loader section the decoders have also undergone a change; although none of them have been written yet.
Instead of operating on a stream of data directly from a file they now operate on a buffer of data. This decouples decoding from loading nicely, which with a bit of refactoring means the whole system can be generalised to deal with whatever resouce type is required.
Right now however things point towards textures, when constructed they are given a chunk of data to work with and an image object to fill with data.
3) The Sync backend
Due to the design this is infact a stupidly easy function to write [grin]
void LoadImageSync(WorkPacket &work)
GameTextureLoader3::DecoderImageData data = work.loaderFunction(work.name); // load all the data in
GameTextureLoader3::DecoderBasePtr decoder = work.decoderCreator(data, work.image); // create a decoder for the data
decoder->Decode(); // and decode the image
Yep, that's all there is to it. WorkPacket contains all the information we need to load the data and decode it and it contains a boost::shared_ptr which points to the data object we end up returning to the user.
4) The default Sync. Loader
This was nice and easy to make, and complete with some nice little C++ tricks the code is compact and concise.
GameTextureLoader3::DecoderImageData DefaultSyncLoader(std::string const &filename)
std::vector<unsigned char> buffer;
std::ifstream file(filename.c_str(), std::ios::binary);
std::istream_iterator<unsigned char> src(file);
std::istream_iterator<unsigned char> eof;
GameTextureLoader3::DecoderImageData data(new GameTextureLoader3::DecoderImageData::element_type[buffer.size()]);
5) The Async backend
The Async backend is what handles all the thread dispatching of files. However, even this was only a few lines of code and again, due to the way the system is put together, we can make our loader function very short indeed;
DWORD WINAPI LoaderThread(LPVOID )
while ( (bRet = GetMessage(&msg, reinterpret_cast
(-1), WM_NEWWORK,WM_QUITTHREAD)) != 0)
WorkPacket *work = reinterpret_cast
Note how we are reusing LoadImageSync() todo the heavy lifting; this is because during setup the loader function selected is the async type, so it will do the right thing (start a transfer, wait the thread) without any custom handling here. Gotta love that code reuse [grin]
6) Async loader
The final thing to be implimented was the async loader, again this is a pretty simple set of functionality really;
- Open the file
- Get its lenght
- Reserve some space
- Create an event which fires when the transfer is complete
- Set the transfer in motion
- Set the thread into a 'wait' state until the transfer is done
- Return the data
This function did bring up one issue; GTL3 uses std::string all over the place, however CreateFile requires a wide character string, at least in my current build setup. Which raises the question of should I convert GTL to support wide characters only? or maybe detect which type and adjust as required? I guess, what with it being 2007 and all I should make a larger effort to convert to unicode/wide characters, however I'm also aware that alot of people don't use unicode/wide characters either. In theory is shouldn't be too hard to deal with, given the limited use of character based functions I'm performing, we'll see.
The big thing I still need to do is convert all the old GTL2.x filters to GTL3.0 decoders; The filters however were pretty sanely put together, infact they tended to load all the data first and then work on it as a buffer anyways, so based on that it shouldn't take too longer to adjust them to something sane.
After that it's a matter of making any changes required to the public image interface (pretty much a state query function) and it's private interface (mostly we need to be able to set the state and the image data) and we are looking good to go.
Oh, and I should probably add some error checking as well [grin]