Sign in to follow this  
dotproduct

Filereaders

Recommended Posts

I'm about to design and write the file input system for my engine. I want to support at least .3ds and .obj for now, and make it easy to add more file formats later. I'll probably have a base class "Filereader", and subclasses (e.g. 3dsReader, OBJReader, etc...) My question is: how can I make it possible to add new file format classes without having to add anything to existing code? Some sort of plugin system I guess (not necessarily dynamically loaded).

Share this post


Link to post
Share on other sites
The best way to deal with this depends on your class layout. Here's one way I might do it:

std::map< std::string , boost::shared_ptr< model_loader > > model_loaders;

struct model_loader
{
virtual void load( model_data & model , const std::string & file ) = 0;
};

struct 3ds_model_loader
{
virtual void load( model_data & model , const std::string & file )
{
std::ifstream ifs( file.c_str() );
ifs >> model._____;
ifs >> model._____;
ifs >> model._____;
}
};

struct obj_model_loader
{
virtual void load( model_data & model , const std::string & file )
{
std::ifstream ifs( file.c_str() );
ifs >> model._____;
ifs >> model._____;
ifs >> model._____;
}
};

void init( void )
{
model_loaders["3ds"] = new 3ds_model_loader;
model_loaders["obj"] = new obj_model_loader;
}

void load_model( model_data & model , const std::string & file )
{
model_loaders[ extension( file ) ]->load( model , file );
}

Share this post


Link to post
Share on other sites
Combine the factory pattern with the chain-of-responsibility (CHOR) pattern. All your readers need to be derived from a common base class, which should look like this:

class Reader {
public:
virtual ~Reader() {}

virtual auto_ptr<Model> read(FileStream &fs) = 0;
virtual bool canRead(FileStream &fs) const = 0;
};


Then write a class to where all available readers are registered and which queries the readers, one by one, whether they can load a given stream using their canRead() method:

class ReaderManager {
public:
void addReader(...) { ... }

auto_ptr<Model> read(FileStream &fs) {
for(
ReaderMap::const_iterator ReaderIt = m_Readers.begin();
ReaderIt != m_Readers.end(); ++ReaderIt
) {
if(ReaderIt->canRead(fs)) {
return ReaderIt->read(fs9;
}
}
}
};


This is the basic approach on how I would do it, of course this can be made more effective by providing various hints to the canRead() method like the file's extension (if available), the first 4 bytes of the file or anything else you might think that helps the reader implementation classes.

-Markus-

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this