The following classes are a C++ implementation of an ngplant to Ogre converter.
This is a somewhat bare-bones implementation, missing such obvious enhancements as customizable generated mesh and material names. It does include the necessary code to make ngp files first class Ogre resources.
This release is labeled version 1.1.
What works:
Material generation
Mesh generation
Usage of serialized mesh files
What's not implemented:
Support for ngplant's built-in LOD scheme
Support for ngplant's AUX0 and AUX1 textures
What's not tested:
Material generation with support for normal textures
No value assigned
Screenshots
Here's a sample of 7 different species of tree, with multiple varieties:
Panoramic sample of trees
Here's a close-up of one of the species:
Close up of an individual
Download
Downloadable 7-Zip archive of all eight source files:
Compile ngpcoreOnly the ngpcore library from ngplant is necessary to use this code. You may use its included SConstruct configuration to build it or simply manually include its source files in your project, either directly or as a library.
Add the eight source files to your project
Add the ngpcore include path to your project
Add the ngpcore link library and path to your project
Add the following somewhere in your project:
The following fragments won't work as-is. You'll need to put them in appropriate places to integrate them with your code.
// Do this somewhere early in your initialization process. It registers the ngpfile type.
// This pointer may be discarded since the NGPFileManager is an Ogre Singleton.
NGPFileManager *ngpFileManager = new NGPFileManager();
// Add a resource path that contains ngp files
Ogre::ResourceGroupmanager::getSingleton().addResourceLocation("media/plants", "Filesystem");
PlantManager pm;
To get different variations of the same plant, pass in a seed:
Caveat
The generated mesh is always named "input.ngp.mesh", so you'll have to remove or rename a mesh generated with a different seed before reusing an ngp file with loadPlant() to avoid a collision in Ogre's resource system.
FIXED - name now "input.ngp_seed.mesh"
Note
This version always serializes the generated mesh and material files to disk when calling loadPlant(). Serious users will probably want to modify that behavior. FIXED - use loadPlantAsMesh() instead, as below.
To load the same plant with seed, but without serializing the mesh and materials to disk:
Entity *entity;
Ogre::MeshPtr mesh_ptr = pm.loadPlantAsMesh("samplefern.ngp", 1234);
if(!mesh_ptr.isNull())
{
OGRE_LOG("Successfully loaded samplefern.ngp")
entity = mSceneManager->createEntity("Sample Fern 1234", mesh_ptr);
// if you wish to later serialize the .mesh and .materials, call:
// pm.serializePlant(mesh_ptr);
}
else
OGRE_LOG("Failed to load samplefern.ngp")
Assuming samplefern.ngp is in the media/plants directory (in this example) and its texture is in the same or another of your resource paths, once this code executes you'll have an Ogre entity suitable for attaching to a SceneNode. It can also be used in Paged Geometry running in DirectX. It will not work correctly in Paged Geometry under OpenGL due to a bug in Paged Geometry. However, if you put the resulting .mesh and .material files into one of your resource paths and create an entity by loading them, it will work just fine in Paged Geometry in either DX or GL.
The latest source code can be found here OgrePlant github.
It includes the fixes suggested in the notes on this page (serialization seperation, file naming), and updates to work with Ogre 1.9.X.
This is a public repository, if you improve the code, please submit your changes on github (pull request).
All of the following eight files are complete in themselves and included in the downloadable archive. They only need to be added to your build system to be used.
//===============================================================================================================
// NGPFile.h v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#ifndef NGPFILE_H
#define NGPFILE_H
#include <OgreResourceManager.h>
#include <ngpcore/p3dhli.h>
#include <sstream>
class NGPFile : public Ogre::Resource, public P3DInputStringStream
{
Ogre::String mString;
std::istringstream *mStream;
protected:
// From Ogre::Resource
void loadImpl();
void unloadImpl();
size_t calculateSize() const;
public:
NGPFile(Ogre::ResourceManager *creator, const Ogre::String &name,
Ogre::ResourceHandle handle, const Ogre::String &group, bool isManual = false,
Ogre::ManualResourceLoader *loader = 0);
virtual ~NGPFile();
void setString(const Ogre::String &str);
const Ogre::String &getString() const;
// From P3DInputStringStream
/** Read interface method required by ngplant
*
* Reads one line at a time from the member string for ngplant to parse.
* \param Buffer Buffer that characters will be written to.
* \param BufferSize Size of buffer being filled.
*/
void ReadString(char *Buffer, unsigned int BufferSize);
bool Eof() const;
};
class NGPFilePtr : public Ogre::SharedPtr<NGPFile>
{
public:
NGPFilePtr() : Ogre::SharedPtr<NGPFile>() {}
explicit NGPFilePtr(NGPFile *rep) : Ogre::SharedPtr<NGPFile>(rep) {}
NGPFilePtr(const NGPFilePtr &r) : Ogre::SharedPtr<NGPFile>(r) {}
NGPFilePtr(const Ogre::ResourcePtr &r) : Ogre::SharedPtr<NGPFile>()
{
if(r.isNull())
return;
// lock & copy other mutex pointer
OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
pRep = static_cast<NGPFile*>(r.getPointer());
pUseCount = r.useCountPointer();
useFreeMethod = r.freeMethod();
if (pUseCount)
{
++(*pUseCount);
}
}
/// Operator used to convert a ResourcePtr to an NGPFilePtr
NGPFilePtr& operator=(const Ogre::ResourcePtr& r)
{
if(pRep == static_cast<NGPFile*>(r.getPointer()))
return *this;
release();
if(r.isNull())
return *this; // resource ptr is null, so the call to release above has done all we need to do.
// lock & copy other mutex pointer
OGRE_LOCK_MUTEX(*r.OGRE_AUTO_MUTEX_NAME)
OGRE_COPY_AUTO_SHARED_MUTEX(r.OGRE_AUTO_MUTEX_NAME)
pRep = static_cast<NGPFile*>(r.getPointer());
pUseCount = r.useCountPointer();
useFreeMethod = r.freeMethod();
if (pUseCount)
{
++(*pUseCount);
}
return *this;
}
};
#endif
//===============================================================================================================
// NGPFileSerializer.h v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#ifndef NGPFILESERIALIZER_H
#define NGPFILESERIALIZER_H
#include <OgreSerializer.h>
class NGPFile;
class NGPFileSerializer : public Ogre::Serializer
{
public:
NGPFileSerializer();
virtual ~NGPFileSerializer();
void exportNGPFile(const NGPFile *pText, const Ogre::String &fileName);
void importNGPFile(Ogre::DataStreamPtr &stream, NGPFile *pDest);
};
#endif