History: OgrePlant
Source of version: 16 (current)
Copy to clipboard
{DIV(type="div",width="50",float="right",bg="#FFFFFF")}
{maketoc}{DIV}
!{img fileId=2038} Description
The following classes are a C++ implementation of an [http://ngplant.sourceforge.net/|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
%ogre18%
%ogre17%
!{img fileId=2121} Screenshots
Here's a sample of 7 different species of tree, with multiple varieties:
{img fileId=2367 rel="box" button="y" stylebox="border" max="800" desc="Panoramic sample of trees"}
Here's a close-up of one of the species:
{img attId=157 rel="box" button="y" stylebox="border" max="300" desc="Close up of an individual"}
!{img fileId=2037} Download
Downloadable 7-Zip archive of all eight source files:
{img fileId=2034 title=Download}{ATTACH(id=163)}{ATTACH}
Alternatively, the latest source can be downloaded from the
[https://github.com/kshepherd2013/OgrePlant/archive/master.zip|OgrePlant github repository]
!{img fileId=2031} Usage
* {MOUSEOVER(text="Only 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.")}Compile ngpcore{MOUSEOVER}
* 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.
First the necessary includes:
{CODE(wrap="1", colors="c++")}#include "OgrePlant.h"
#include "NGPFileManager.h"{CODE}
Then initialization:
{CODE(wrap="1", colors="c++")}// 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;{CODE}
Then to create a plant:
{CODE(wrap="1", colors="c++")}Entity *entity;
if(pm.loadPlant("samplefern.ngp"))
{
OGRE_LOG("Successfully loaded samplefern.ngp")
entity = mSceneManager->createEntity("Sample Fern", "samplefern.ngp.mesh");
}
else
OGRE_LOG("Failed to load samplefern.ngp"){CODE}
To get different variations of the same plant, pass in a seed:
{BOX(width="24%",float="right")}{REMARKSBOX(type="warning",title="Caveat",highlight="n")}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" {REMARKSBOX}{REMARKSBOX(type="note",title="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.{REMARKSBOX}{BOX}
{CODE(wrap="1", colors="c++")}Entity *entity;
if(pm.loadPlant("samplefern.ngp", 1234))
{
OGRE_LOG("Successfully loaded samplefern.ngp")
entity = mSceneManager->createEntity("Sample Fern 1234", "samplefern.ngp.mesh");
}
else
OGRE_LOG("Failed to load samplefern.ngp"){CODE}
To load the same plant with seed, but without serializing the mesh and materials to disk:
{CODE(wrap="1", colors="c++")}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"){CODE}
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.
!-{img fileId=2031} Source
The latest source code can be found here [https://github.com/kshepherd2013/OgrePlant|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.
!!{img fileId=2032} Header Files
!!!-{img fileId=2032} OgrePlant.h
{CODE(wrap="1", caption="OgrePlant.h", colors="c++")}//===============================================================================================================
// OgrePlant.h v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#ifndef OGREPLANT_H
#define OGREPLANT_H
#define OGRE_LOG(message) Ogre::LogManager::getSingleton().logMessage(message)
class P3DMaterialDef;
class PlantManager
{
private:
const Ogre::String createMaterial(const std::string &baseName, const int groupIndex, const P3DMaterialDef *material, bool &textured,
const Ogre::String &resourceGroup = Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
public:
bool loadPlant(const std::string &filename, unsigned int seed = 0, const Ogre::String &resourceGroup = Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
};
#endif{CODE}
!!!-{img fileId=2032} NGPFile.h
{CODE(wrap="1", caption="NGPFile.h", colors="c++")}//===============================================================================================================
// 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{CODE}
!!!-{img fileId=2032} NGPFileSerializer.h
{CODE(wrap="1", caption="NGPFileSerializer.h", colors="c++")}//===============================================================================================================
// 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{CODE}
!!!-{img fileId=2032} NGPFileManager.h
{CODE(wrap="1", caption="NGPFileManager.h", colors="c++")}//===============================================================================================================
// NGPFileManager.h v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#ifndef NGPFILEMANAGER_H
#define NGPFILEMANAGER_H
#include <OgreResourceManager.h>
#include "NGPFile.h"
class NGPFileManager : public Ogre::ResourceManager, public Ogre::Singleton<NGPFileManager>
{
protected:
// From ResourceManager's interface
Ogre::Resource *createImpl(const Ogre::String &name, Ogre::ResourceHandle handle,
const Ogre::String &group, bool isManual,
Ogre::ManualResourceLoader *loader,
const Ogre::NameValuePairList *createParams);
public:
NGPFileManager();
virtual ~NGPFileManager();
virtual NGPFilePtr load(const Ogre::String &name, const Ogre::String &group);
static NGPFileManager &getSingleton();
static NGPFileManager *getSingletonPtr();
};
#endif{CODE}
!!{img fileId=2031} Source Files
!!!-{img fileId=2031} OgrePlant.cpp
{CODE(wrap="1", caption="OgrePlant.cpp", colors="c++")}//===============================================================================================================
// OgrePlant.cpp v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#include "OgrePlant.h"
#include "NGPFileManager.h"
#include <ngpcore/p3dhli.h>
bool PlantManager::loadPlant(const std::string &filename, unsigned int seed, const Ogre::String &resourceGroup)
{
bool result = false;
unsigned int branchGroupCount, totalPolys = 0;
Ogre::MeshManager &mm = Ogre::MeshManager::getSingleton();
NGPFileManager &nm = NGPFileManager::getSingleton();
try
{
NGPFile *ngp = nm.load(filename, resourceGroup).getPointer();
P3DHLIPlantTemplate plantTemplate(ngp);
P3DHLIPlantInstance *plantInstance;
plantInstance = plantTemplate.CreateInstance(seed);
branchGroupCount = plantTemplate.GetGroupCount();
Ogre::MeshPtr mesh = mm.createManual(filename + ".mesh", resourceGroup);
if(branchGroupCount > 0)
{
bool fullyTextured = true;
for(unsigned int i = 0; i < branchGroupCount; ++i)
{
unsigned int branchCount = plantInstance->GetBranchCount(i);
unsigned int vertexCount = plantInstance->GetVAttrCountI(i); // equal to template attrCount * instance branchCount
unsigned int indexCount = plantTemplate.GetIndexCount(i, P3D_TRIANGLE_LIST);
unsigned int branchAttrCount = plantTemplate.GetVAttrCountI(i); // number of vertices in a single branch model
bool textured = false;
Ogre::SubMesh *submesh = mesh->createSubMesh();
submesh->setMaterialName(createMaterial(filename, i, plantTemplate.GetMaterial(i), textured, resourceGroup));
submesh->useSharedVertices = false;
submesh->vertexData = new Ogre::VertexData();
submesh->vertexData->vertexStart = 0;
submesh->vertexData->vertexCount = vertexCount;
submesh->indexData->indexStart = 0;
submesh->indexData->indexCount = indexCount * branchCount;
totalPolys += submesh->indexData->indexCount/3;
Ogre::VertexData *vertexData = submesh->vertexData;
// Vertex format definitions...
// ... for Ogre...
Ogre::VertexDeclaration *vertexDecl = vertexData->vertexDeclaration;
size_t currOffset = 0;
vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
if(textured)
{
vertexDecl->addElement(0, currOffset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
}
// ... and for ngplant.
P3DHLIVAttrFormat format = P3DHLIVAttrFormat(currOffset);
currOffset = 0;
format.AddAttr(P3D_ATTR_VERTEX, currOffset);
currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
format.AddAttr(P3D_ATTR_NORMAL, currOffset);
currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
if(textured)
{
format.AddAttr(P3D_ATTR_TEXCOORD0, currOffset);
currOffset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
}
// Allocate, lock, and get a pointer to the vertex buffer.
Ogre::HardwareVertexBufferSharedPtr vBuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC, true);
Ogre::VertexBufferBinding* binding = vertexData->vertexBufferBinding;
binding->setBinding(0, vBuf);
float* pVertex = static_cast<float*>(vBuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
// Allocate, lock, and get a pointer to the index buffer.
submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, submesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
Ogre::HardwareIndexBufferSharedPtr iBuf = submesh->indexData->indexBuffer;
unsigned short *pIndices = static_cast<unsigned short *>(iBuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
// Copy vertex data.
plantInstance->FillVAttrBufferI((void *)pVertex, i, &format);
// Flip UVs, if there are any.
if(textured)
{
size_t offset = vertexDecl->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES)->getOffset()/sizeof(float);
for(unsigned int j = 0; j < vertexCount*vertexDecl->getVertexSize(0)/sizeof(float); j+=vertexDecl->getVertexSize(0)/sizeof(float))
{
pVertex[j+offset] = -pVertex[j+offset];
pVertex[j+offset+1] = -pVertex[j+offset+1];
}
}
// Copy index data.
for(unsigned int branchIndex = 0; branchIndex < branchCount; ++branchIndex)
{
plantTemplate.FillIndexBuffer(&(pIndices[branchIndex * indexCount]), i, P3D_TRIANGLE_LIST, P3D_UNSIGNED_SHORT, branchIndex * branchAttrCount);
}
vBuf->unlock();
iBuf->unlock();
fullyTextured &= textured;
}
float minBound[3], maxBound[3];
plantInstance->GetBoundingBox(minBound, maxBound);
mesh->_setBounds(Ogre::AxisAlignedBox(minBound[0], minBound[1], minBound[2], maxBound[0], maxBound[1], maxBound[2]));
mesh->_setBoundingSphereRadius(mesh->getBounds().getHalfSize().length());
mesh->load();
unsigned short src, dest;
if(fullyTextured && !mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src, dest))
{
mesh->buildTangentVectors(Ogre::VES_TANGENT, src, dest, true, true);
}
result = true;
Ogre::Mesh::SubMeshIterator smIt = mesh->getSubMeshIterator();
while(smIt.hasMoreElements())
{
Ogre::SubMesh *sm = smIt.getNext();
if(!sm->useSharedVertices)
{
Ogre::VertexDeclaration *autoDeclaration = sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(false, false);
if(*autoDeclaration != *(sm->vertexData->vertexDeclaration))
{
Ogre::BufferUsageList bufferUsages;
for(size_t u = 0; u <= autoDeclaration->getMaxSource(); ++u)
bufferUsages.push_back(Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
sm->vertexData->reorganiseBuffers(autoDeclaration, bufferUsages);
}
}
}
Ogre::MeshSerializer meshSerializer;
meshSerializer.exportMesh(mesh.getPointer(), mesh->getName());
}
else
{
OGRE_LOG("Loaded empty plant template " + filename);
}
delete plantInstance;
}
catch(const P3DException &exc)
{
OGRE_LOG("ngplant load error: " + std::string(exc.GetMessage()));
}
OGRE_LOG("Poly count: " + Ogre::StringConverter::toString(totalPolys));
return result;
}
const Ogre::String PlantManager::createMaterial(const std::string &baseName, const int groupIndex, const P3DMaterialDef *material,
bool &textured, const Ogre::String &resourceGroupName)
{
std::string matName;
Ogre::MaterialPtr mat;
Ogre::MaterialManager &mm = Ogre::MaterialManager::getSingleton();
const char *texName = material->GetTexName(P3D_TEX_DIFFUSE);
if(texName == NULL)
{
matName = baseName + "_" + toString<int>(groupIndex) + ".material";
textured = false;
}
else
{
matName = baseName + "_" + texName + ".material";
textured = true;
}
if(!mm.resourceExists(matName))
{
float r, g, b;
#ifdef SUPPORT_NORMALS
const char *normName = material->GetTexName(P3D_TEX_NORMAL_MAP);
if(normName != NULL)
{
Ogre::MaterialPtr parent = mm.getByName("Examples/BumpMapping/MultiLight");
mat = parent->clone(matName, true, resourceGroupName);
Ogre::Technique *technique = mat->getTechnique(0);
Ogre::Pass *perlight = technique->getPass("perlight");
perlight->setLightingEnabled(true);
Ogre::TextureUnitState *normalTexture = perlight->getTextureUnitState("normalmap");
normalTexture->setTextureName(normName);
if(texName != NULL)
{
Ogre::Pass *decal = technique->getPass("decal");
if(material->IsTransparent())
{
decal->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
decal->setCullingMode(Ogre::CULL_NONE);
decal->setManualCullingMode(Ogre::MANUAL_CULL_NONE);
decal->setAlphaRejectSettings(Ogre::CMPF_GREATER_EQUAL, (unsigned char)200);
}
Ogre::TextureUnitState *decalTexture = decal->getTextureUnitState("decalmap");
decalTexture->setTextureName(texName);
}
}
else
{
#endif
mat = mm.create(matName, resourceGroupName);
mat->_notifyOrigin("OgrePlant");
Ogre::Technique *technique = mat->getTechnique(0);
Ogre::Pass *pass = technique->getPass(0);
Ogre::TextureUnitState *textureUnit;
if(texName != NULL)
{
textureUnit = pass->createTextureUnitState();
textureUnit->setTextureName(texName);
}
material->GetColor(&r, &g, &b);
mat->setDiffuse(r, g, b, 1.0f);
mat->setAmbient(r, g, b);
if(material->IsTransparent())
{
pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
pass->setCullingMode(Ogre::CULL_NONE);
pass->setManualCullingMode(Ogre::MANUAL_CULL_NONE);
pass->setAlphaRejectSettings(Ogre::CMPF_GREATER_EQUAL, (unsigned char)200);
pass->setAlphaToCoverageEnabled(true);
// Documentation seems to imply this is relevant only with single-channel
// images, but manually written materials have the parameter. Test each way.
if(texName != NULL)
textureUnit->setIsAlpha(true);
}
#ifdef SUPPORT_NORMALS
}
#endif
Ogre::MaterialSerializer materialSerializer;
materialSerializer.exportMaterial(mat, mat->getName());
}
// !!TODO!! P3D_TEX_AUX0 and P3D_TEX_AUX1
texName = material->GetTexName(P3D_TEX_AUX0);
if(texName != NULL)
OGRE_LOG("Template has AUX0 texture");
texName = material->GetTexName(P3D_TEX_AUX1);
if(texName != NULL)
OGRE_LOG("Template has AUX1 texture");
return matName;
}{CODE}
!!!-{img fileId=2031} NGPFile.cpp
{CODE(wrap="1", caption="NGPFile.cpp", colors="c++")}//===============================================================================================================
// NGPFile.cpp v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#include "NGPFile.h"
#include "NGPFileSerializer.h"
NGPFile::NGPFile(Ogre::ResourceManager *creator, const Ogre::String &name,
Ogre::ResourceHandle handle, const Ogre::String &group,
bool isManual, Ogre::ManualResourceLoader *loader)
: Ogre::Resource(creator, name, handle, group, isManual, loader)
{
}
NGPFile::~NGPFile()
{
unload();
}
void NGPFile::loadImpl()
{
NGPFileSerializer serializer;
Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(mName, mGroup, true, this);
serializer.importNGPFile(stream, this);
mStream = new std::istringstream(mString);
}
void NGPFile::unloadImpl()
{
mString.clear();
delete mStream;
}
size_t NGPFile::calculateSize() const
{
// An approximation
return mString.length() + sizeof(*mStream);
}
void NGPFile::setString(const Ogre::String &str)
{
mString = str;
}
const Ogre::String &NGPFile::getString() const
{
return mString;
}
void NGPFile::ReadString(char *Buffer, unsigned int BufferSize)
{
mStream->getline(Buffer, BufferSize);
// If reading DOS format file, stomp on carriage return byte
if(Buffer[mStream->gcount()-2] == '\r')
Buffer[mStream->gcount()-2] = '\0';
}
bool NGPFile::Eof() const
{
return mStream->eof();
}{CODE}
!!!-{img fileId=2031} NGPFileSerializer.cpp
{CODE(wrap="1", caption="NGPFileSerializer.cpp", colors="c++")}//===============================================================================================================
// NGPFileSerializer.cpp v1.0
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#include "NGPFileSerializer.h"
#include "NGPFile.h"
NGPFileSerializer::NGPFileSerializer()
{
}
NGPFileSerializer::~NGPFileSerializer()
{
}
void NGPFileSerializer::exportNGPFile(const NGPFile *pText, const Ogre::String &fileName)
{
std::ofstream outFile;
outFile.open(fileName.c_str(), std::ios::out);
outFile << pText->getString();
outFile.close();
}
void NGPFileSerializer::importNGPFile(Ogre::DataStreamPtr &stream, NGPFile *pDest)
{
pDest->setString(stream->getAsString());
}{CODE}
!!!-{img fileId=2031} NGPFileManager.cpp
{CODE(wrap="1", caption="NGPFileManager.cpp", colors="c++")}//===============================================================================================================
// NGPFileManager.cpp v1.1
// Written by DragonM, this file is released into the public domain.
//===============================================================================================================
#include "NGPFileManager.h"
#if OGRE_VERSION_MINOR == 8
template<> NGPFileManager *Ogre::Singleton<NGPFileManager>::msSingleton = 0;
#else
template<> NGPFileManager *Ogre::Singleton<NGPFileManager>::ms_Singleton = 0;
#endif
NGPFileManager *NGPFileManager::getSingletonPtr()
{
#if OGRE_VERSION_MINOR == 8
return msSingleton;
#else
return ms_Singleton;
#endif
}
NGPFileManager &NGPFileManager::getSingleton()
{
#if OGRE_VERSION_MINOR == 8
assert(msSingleton);
return(msSingleton);
#else
assert(ms_Singleton);
return(*ms_Singleton);
#endif
}
NGPFileManager::NGPFileManager()
{
mResourceType = "NGPFile";
// low, because it will likely reference other resources
mLoadOrder = 30.0f;
// register the ResourceManager with OGRE
Ogre::ResourceGroupManager::getSingleton()._registerResourceManager(mResourceType, this);
}
NGPFileManager::~NGPFileManager()
{
// unregister from OGRE
Ogre::ResourceGroupManager::getSingleton()._unregisterResourceManager(mResourceType);
}
NGPFilePtr NGPFileManager::load(const Ogre::String &name, const Ogre::String &group)
{
NGPFilePtr textf = getByName(name);
if(textf.isNull())
textf = create(name, group);
textf->load();
return textf;
}
Ogre::Resource *NGPFileManager::createImpl(const Ogre::String &name, Ogre::ResourceHandle handle,
const Ogre::String &group, bool isManual, Ogre::ManualResourceLoader *loader,
const Ogre::NameValuePairList *createParams)
{
return new NGPFile(this, name, handle, group, isManual, loader);
}{CODE}
!{img fileId=2036} Compatibility
This code is known to work in Ogre 1.7 and Ogre 1.8 and Ogre 1.9.