Skip to main content.

Introduction

This page serves as a reference to a couple of key concepts to be aware of when using this library.

User Defined Read/Seek functions

While the GTL can read from standard files and even from PhysFS file handles there might be times when the end user wishes to read from other sources, such as memory or maybe even a network stream. To this end the GTL has a loader function which takes function objects which can perform this reading and seeking. This section of the docs serves as a quick introduction to how to write these functions.

The reading function is pretty simple. First you must make a function which matches the call signature of the type def ReadFunc_t, as this will be used as a call back to perform the reading. When called the function will be given a max amount to read and a location to place the data. The read function should read as much of the requested amout as it can, place the data into the memory space provided and return the amount read. This amount can be less than the requested size if required.

If the end of the data has been reached then the reader must return -1 (minus one) to indicate end of the data to the calling function.

When it comes to seeking this as a little bit different as the seeking function has to be able to deal with 2 modes of seeking, from the current location (std::ios_base::cur) and from the begining of the data stream (std::ios_base::beg). This seeking could possibly go in both forward and backwards directions. It is upto the seeker to deal with both of this conditions properly.

If the seek cant be performed then the seeker function should return -1 (minus one) to indicate it failed. Otherwise, it should return the offset into the stream from the begining of the stream.

The PhysFS device gives some clues as to how the reader and seeker functions should be written.

Controlling the build process.

The GTL was designed with ease of reconfiguation in mind, as such when you are building it you can set various options to control the build process of the library.

The simplest way to control the build process is to edit the config.hpp file in the include directory. By commenting out the various GTL_*_FILTER defines you can remove the loaders from the build process. There is also a define there to enable PhysFS support, by removing this you prevent the inclusion of the device needed to read from PhysFS files.

Adding additional loaders/filters at compile time.

The best guide for doing this is to look at the source for the current filters/loaders (the BMP one being the simplest). However this is a quick guide on how to add your own decoders.

Firstly, it MUST be copy constructable. Failure for it to work correctly when copies will cause things to go wrong at some point.
Your class must derive from FilterBase. This is required as all we pass around are references to FilterBase.
The read function must match the signature : virtual std::streamsize read(streambuf_t *src,char * s, std::streamsize n). Where 'n' is the amount to read in, 's' is the location to place the data and 'src' is a pointer to the buffer to read from. The function must return the amount placed into the 's' buffer or -1 (minus one) if the end of the data has been reached.
On the first entry into the read function you MUST fill out the header infomation (which is supplied to you as a reference in the constructor), as this infomation is required for the loading process to work correctly.
You must supply a function to construct the filter class, for example from the BMP filter;

    filterptr MakeBitmapFilter(LoaderImgData &imgdata)
    {
  • return filterptr(new bitmapfilter(imgdata));
  • }

This constructs a new bmp loader and wraps in a filterptr object. To use this in your own code you'd replace bitmapfilter with your own class name.
Next you need to add an entry in the FileTypes enum so that people can request your new filter type.
Then you need to register your filter type with the system via the following macro;

  • DECLARE_TEXTURE_LOADER(TYPE_BMP, "BMP",MakeBitmapFilter)

In this case the macro is registering the bitmap creation function above so that it can be found via the FileTypes value 'TYPE_BMP' and via the file extension "BMP". To customise this for your own file type you would need to change the TYPE_BMP to your newly added type and give it the extension of your file type as the 2nd parameter. Once this is done the creation function will be registered with the system so that you can load your type of image in.

The last two steps are pretty simple. Firstly you need to add the header file you created your filter in to the Filters.hpp file, complete with the inclusion check like the ones which already exist and finally in config.hpp you need to add the same define to the build section of the header file so that your new filter is included when the lib is built.

Congratulations, you've just added a new file loader to the system.

Adding additional loaders/filters at run time.

GTL exposes two functions to do this, both of which require you to include the header "GTLRunTimeTextureFilter.hpp" in your application.

Once this is done you can register your filter creation function by calling RegisterFilter(), which requires a filename extension and a a functor to a function which will create the function. The functor's signature must match the signature of FilterCreator_t, which is the same as the MakeBitmapFilter example above. This creation function will be called whenever a new filter of that type needs to be created to load a texture and must work as detailed in the section above. The RegisterFilter() function also returns an id which can be used to load your textures via the LoadTexture() & LoadTextureSafe() functions.

It is also possible to unregister a loader/filter at runtime. Todo this you need to call the function UnRegisterFunction() and supply it with the id returned from RegisterFilter(). Once this has been done you will no longer be able to load texture data of that type via the GTL.

Copyright © 2004, Rob Jones