M2MeshFile loader 0.2

-Texturing (one layer only)
-alpha transparency and backface culling flags handled
-various fixes
This commit is contained in:
shlainn 2008-04-06 02:25:24 +00:00
parent b4ece10cb1
commit 1a79b45b99
2 changed files with 486 additions and 309 deletions

View File

@ -1,158 +1,287 @@
#include <iostream> #include <iostream>
#include "CM2MeshFileLoader.h" #include "CM2MeshFileLoader.h"
namespace irr
{
namespace scene namespace irr
{ {
namespace scene
CM2MeshFileLoader::CM2MeshFileLoader(IrrlichtDevice* device):Device(device) {
{
CM2MeshFileLoader::CM2MeshFileLoader(IrrlichtDevice* device, c8* basedir):Device(device), Basedir(basedir)
} {
CM2MeshFileLoader::~CM2MeshFileLoader() }
{
CM2MeshFileLoader::~CM2MeshFileLoader()
} {
}
bool CM2MeshFileLoader::isALoadableFileExtension(const c8* filename)const
{
return strstr(filename, ".m2")!=0; bool CM2MeshFileLoader::isALoadableFileExtension(const c8* filename)const
} {
return strstr(filename, ".m2")!=0;
}
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! creates/loads an animated mesh from the file.
//! See IUnknown::drop() for more information. //! \return Pointer to the created mesh. Returns 0 if loading failed.
IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file) //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
{ //! See IUnknown::drop() for more information.
ILogger* logger =Device->getLogger(); IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file)
{
logger->log("Trying to open file",file->getFileName(),ELL_INFORMATION); ILogger* logger =Device->getLogger();
logger->log("Trying to open file",file->getFileName(),ELL_INFORMATION);
file->read(&header,sizeof(ModelHeader));
if (header.version[0] != 4 && header.version[1] != 1 && header.version[2] != 0 && header.version[3] != 0) {
logger->log("Something wrong!",ELL_ERROR); file->read(&header,sizeof(ModelHeader));
return 0; if (header.version[0] != 4 && header.version[1] != 1 && header.version[2] != 0 && header.version[3] != 0) {
} logger->log("Something wrong!",ELL_ERROR);
else logger->log(L"header okay",ELL_INFORMATION); return 0;
//Name -> not very important I think, but save it nontheless; }
std::cout << "Name offset:" << header.nameOfs << "Name length:" << header.nameLength << "\n"; else logger->log(L"header okay",ELL_INFORMATION);
file->seek(header.nameOfs); //Name -> not very important I think, but save it nontheless;
file->read(&M2MeshName[0],header.nameLength); std::cout << "Name offset:" << header.nameOfs << "Name length:" << header.nameLength << "\n";
std::cout << "Read name:"<<M2MeshName.c_str()<<"\n"; //M2MeshName.clear();
//logger->log("Mesh Name",M2MeshName.c_str(),ELL_INFORMATION); //M2MeshName.reserve(header.nameLength);
//Now we load all kinds of data from the file file->seek(header.nameOfs);
// file->read(&M2MeshName[0],header.nameLength);
//Vertices //std::cout << "Read name:"<<M2MeshName.c_str()<<"Size: "<< M2MeshName.size() <<"|"<<M2MeshName[0]<< "\n";
if(!M2MVertices.empty()) //logger->log("Mesh Name",M2MeshName.c_str(),ELL_INFORMATION);
M2MVertices.clear(); //Now we load all kinds of data from the file
ModelVertex tempM2MVert; //Vertices. Global data
file->seek(header.ofsVertices); if(!M2MVertices.empty())
M2MVertices.clear();
for(u32 i =0;i<header.nVertices;i++)
{ ModelVertex tempM2MVert;
file->read(&tempM2MVert,sizeof(ModelVertex)); file->seek(header.ofsVertices);
M2MVertices.push_back(tempM2MVert);
} for(u32 i =0;i<header.nVertices;i++)
std::cout << "Read "<<M2MVertices.size()<<"/"<<header.nVertices<<" Vertices\n"; {
file->read(&tempM2MVert,sizeof(ModelVertex));
//Views == Sets of vertices. Usage yet unknown M2MVertices.push_back(tempM2MVert);
if(M2MViews.size()>0) }
M2MViews.clear(); std::cout << "Read "<<M2MVertices.size()<<"/"<<header.nVertices<<" Vertices\n";
ModelView tempM2MView;
file->seek(header.ofsViews); //Views == Sets of vertices. Usage yet unknown. Global data
for(u32 i =0;i<header.nViews;i++) if(M2MViews.size()>0)
{ M2MViews.clear();
file->read(&tempM2MView,sizeof(ModelView)); ModelView tempM2MView;
M2MViews.push_back(tempM2MView); file->seek(header.ofsViews);
} for(u32 i =0;i<header.nViews;i++)
std::cout << "Read "<<M2MViews.size()<<"/"<<header.nViews<<" Views\n"; {
file->read(&tempM2MView,sizeof(ModelView));
logger->log("Using View 0 for all further operations",ELL_INFORMATION); M2MViews.push_back(tempM2MView);
}
//Vertex indices of a specific view. std::cout << "Read "<<M2MViews.size()<<"/"<<header.nViews<<" Views\n";
if(M2MIndices.size()>0)
M2MIndices.clear(); logger->log("Using View 0 for all further operations",ELL_INFORMATION);
std::cout<<"This View has "<<M2MViews[0].nSub<<" Submeshes\n";
u16 tempM2Index;
file->seek(M2MViews[0].ofsIndex); //Vertex indices of a specific view.Local to View 0
for(u32 i =0;i<M2MViews[0].nIndex;i++) if(M2MIndices.size()>0)
{ M2MIndices.clear();
file->read(&tempM2Index,sizeof(u16));
M2MIndices.push_back(tempM2Index); u16 tempM2Index;
} file->seek(M2MViews[0].ofsIndex);
std::cout << "Read "<<M2MIndices.size()<<"/"<<M2MViews[0].nIndex<<" Indices\n"; for(u32 i =0;i<M2MViews[0].nIndex;i++)
{
file->read(&tempM2Index,sizeof(u16));
//Triangles. Data Points point to the Vertex Indices, not the vertices themself. 3 Points = 1 Triangle M2MIndices.push_back(tempM2Index);
if(M2MTriangles.size()>0) }
M2MTriangles.clear(); std::cout << "Read "<<M2MIndices.size()<<"/"<<M2MViews[0].nIndex<<" Indices\n";
u16 tempM2Triangle;
file->seek(M2MViews[0].ofsTris); //Triangles. Data Points point to the Vertex Indices, not the vertices themself. 3 Points = 1 Triangle, Local to View 0
for(u32 i =0;i<M2MViews[0].nTris;i++) if(M2MTriangles.size()>0)
{ M2MTriangles.clear();
file->read(&tempM2Triangle,sizeof(u16));
M2MTriangles.push_back(tempM2Triangle); u16 tempM2Triangle;
} file->seek(M2MViews[0].ofsTris);
std::cout << "Read "<<M2MTriangles.size()<<"/"<<M2MViews[0].nTris<<" Triangle Indices\n"; for(u32 i =0;i<M2MViews[0].nTris;i++)
{
//Texture Lookup table. file->read(&tempM2Triangle,sizeof(u16));
file->seek(header.ofsTexLookup); M2MTriangles.push_back(tempM2Triangle);
for(u32 i=0;i<header.nTexLookup;i++) }
{ std::cout << "Read "<<M2MTriangles.size()<<"/"<<M2MViews[0].nTris<<" Triangle Indices\n";
} //Submeshes, Local to View 0
if(M2MSubmeshes.size()>0)
//Now, M2MTriangles refers to M2MIndices and not to M2MVertices. M2MSubmeshes.clear();
//And M2MVertices are not usable like this. Thus we transform
if(M2Vertices.size()>0) ModelViewSubmesh tempM2Submesh;
M2Vertices.clear(); file->seek(M2MViews[0].ofsSub);
for(u32 i =0;i<M2MViews[0].nSub;i++)
for(u32 i=0;i<M2MVertices.size();i++) {
{ file->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
M2Vertices.push_back(video::S3DVertex(M2MVertices[i].pos,M2MVertices[i].normal, video::SColor(255,100,100,100),M2MVertices[i].texcoords)); M2MSubmeshes.push_back(tempM2Submesh);
} // std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n";
if(M2Indices.size()>0) }
M2Indices.clear(); std::cout << "Read "<<M2MSubmeshes.size()<<"/"<<M2MViews[0].nSub<<" Submeshes\n";
for(u32 i=0;i<M2MTriangles.size();i++) //Texture units. Local to view 0
{ TextureUnit tempM2TexUnit;
M2Indices.push_back(M2MIndices[M2MTriangles[i]]); if(!M2MTextureUnit.empty())
} {
M2MTextureUnit.clear();
Mesh=new SMesh(); }
file->seek(M2MViews[0].ofsTex);
for(u32 i=0;i<M2MViews[0].nTex;i++)
SMeshBuffer* IMB = new SMeshBuffer; {
while(Mesh->getMeshBufferCount()>0) file->read(&tempM2TexUnit,sizeof(TextureUnit));
{ M2MTextureUnit.push_back(tempM2TexUnit);
Mesh->MeshBuffers.erase(0); }
} std::cout << "Read "<<M2MTextureUnit.size()<<" Texture Unit entries for View 0\n";
std::cout << "Sending "<<M2Vertices.size() <<" Vertices and " << M2Indices.size() <<" Indices to the MeshBuffer\n";
IMB->append(M2Vertices.const_pointer(),M2Vertices.size(),M2Indices.const_pointer(),M2Indices.size());
IMB->recalculateBoundingBox(); //Texture Lookup table. This is global data
Mesh->addMeshBuffer(IMB); u16 tempM2TexLookup;
IMB->drop(); if(!M2MTextureLookup.empty())
aniMesh= new SAnimatedMesh(); {
M2MTextureLookup.clear();
}
aniMesh->addMesh(Mesh); file->seek(header.ofsTexLookup);
Mesh->drop(); for(u32 i=0;i<header.nTexLookup;i++)
Mesh = 0; {
file->read(&tempM2TexLookup,sizeof(u16));
aniMesh->recalculateBoundingBox(); M2MTextureLookup.push_back(tempM2TexLookup);
}
return aniMesh; std::cout << "Read "<<M2MTextureLookup.size()<<" Texture lookup entries\n";
}
//Texture Definitions table. This is global data
} TextureDefinition tempM2TexDef;
} if(!M2MTextureDef.empty())
{
M2MTextureDef.clear();
}
file->seek(header.ofsTextures);
for(u32 i=0;i<header.nTextures;i++)
{
file->read(&tempM2TexDef,sizeof(TextureDefinition));
M2MTextureDef.push_back(tempM2TexDef);
}
std::cout << "Read "<<M2MTextureDef.size()<<" Texture Definition entries\n";
//Render Flags table. This is global data
RenderFlags tempM2RF;
if(!M2MRenderFlags.empty())
{
M2MRenderFlags.clear();
}
file->seek(header.ofsTexFlags);
for(u32 i=0;i<header.nTexFlags;i++)
{
file->read(&tempM2RF,sizeof(RenderFlags));
M2MRenderFlags.push_back(tempM2RF);
}
std::cout << "Read "<<M2MRenderFlags.size()<<" Render Flags\n";
//std::cout << M2MTextureUnit[0].submeshIndex1 <<","<<M2MTextureUnit[0].submeshIndex1 <<","<<M2MTextureUnit[0].textureIndex<<";\n";
if(!M2MTextureFiles.empty())
M2MTextureFiles.clear();
std::string tempTexFileName="";
M2MTextureFiles.reallocate(M2MTextureDef.size());
for(u32 i=0; i<M2MTextureDef.size(); i++)
{
file->seek(M2MTextureDef[i].texFileOfs);
file->read(&tempTexFileName[0],M2MTextureDef[i].texFileLen);
M2MTextureFiles.push_back(tempTexFileName.c_str());
std::cout<<M2MTextureFiles.size()<<"-"<<M2MTextureFiles[i].c_str()<<"\n";
}
// std::cout << "Read "<<M2MTextureFiles.size()<<"/"<<M2MTextureDef.size()<<" Texture file names\n";
//And M2MVertices are not usable like this. Thus we transform
if(M2Vertices.size()>0)
M2Vertices.clear();
for(u32 i=0;i<M2MVertices.size();i++)
{
M2Vertices.push_back(video::S3DVertex(M2MVertices[i].pos,M2MVertices[i].normal, video::SColor(255,100,100,100),M2MVertices[i].texcoords));
}
if (Mesh)
Mesh->drop();
Mesh=new SMesh();
while(Mesh->getMeshBufferCount()>0)
{
Mesh->MeshBuffers.erase(0);
}
for(u32 i=0; i < M2MViews[0].nSub;i++)//
{
//std::cout << "Proceeding with Submesh "<<i<<"/"<<M2MViews[0].nSub<<"\n";
//Now, M2MTriangles refers to M2MIndices and not to M2MVertices.
if(M2Indices.size()>0)
M2Indices.clear();
for(u32 j=M2MSubmeshes[i].ofsTris;j<M2MSubmeshes[i].ofsTris+M2MSubmeshes[i].nTris;j++)
{
M2Indices.push_back(M2MIndices[M2MTriangles[j]]);
}
//std::cout << "Sending "<<M2Vertices.size() <<" Vertices and " << M2Indices.size() <<" Indices to the MeshBuffer\n";
IMB = new SMeshBuffer;
IMB->append(M2Vertices.const_pointer(),M2Vertices.size(),M2Indices.const_pointer(),M2Indices.size());
IMB->recalculateBoundingBox();
//IMB->getMaterial().DiffuseColor.set(255,255-(u32)(255/(M2MSubmeshes.size()))*i,(u32)(255/(M2MSubmeshes.size()))*i,0);
//IMB->getMaterial().DiffuseColor.set(255,(M2MSubmeshes[i].meshpartId==0?0:255),(M2MSubmeshes[i].meshpartId==0?255:0),0);
std::string TexName=Basedir.c_str();
TexName+="/";
TexName+=M2MTextureFiles[M2MTextureUnit[i].textureIndex].c_str();
while(TexName.find('\\')<TexName.size())//Replace \ by /
{
TexName.replace(TexName.find('\\'),1,"/");
}
while(TexName.find(' ')<TexName.size())//Replace space by _
{
TexName.replace(TexName.find(' '),1,"_");
}
std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);
IMB->getMaterial().setTexture(0,Device->getVideoDriver()->getTexture(TexName.c_str()));
std::cout<<M2MRenderFlags[i].flags<<"--"<<M2MRenderFlags[i].blending<<"\n";
IMB->getMaterial().BackfaceCulling=(M2MRenderFlags[i].flags & 0x04)?false:true;
if(M2MRenderFlags[i].blending==1)
IMB->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
Mesh->addMeshBuffer(IMB);
IMB->drop();
//std::cout << "Mesh now has "<<Mesh->getMeshBufferCount()<<" Buffers\n";
}
aniMesh= new SAnimatedMesh();
aniMesh->addMesh(Mesh);
Mesh->drop();
Mesh = 0;
aniMesh->recalculateBoundingBox();
return aniMesh;
}
}
}

View File

@ -1,151 +1,199 @@
#include "irrlicht/irrlicht.h" #include "irrlicht/irrlicht.h"
#include "irrlicht/IMeshLoader.h" #include "irrlicht/IMeshLoader.h"
#include <string>
#include <vector>
namespace irr
{ namespace irr
namespace scene {
{ namespace scene
{
class CM2MeshFileLoader : public IMeshLoader
{ class CM2MeshFileLoader : public IMeshLoader
public: {
public:
//! Constructor
CM2MeshFileLoader(IrrlichtDevice* device); //! Constructor
CM2MeshFileLoader(IrrlichtDevice* device, c8* basedir);
//! destructor
~CM2MeshFileLoader(); //! destructor
virtual ~CM2MeshFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob") //! returns true if the file maybe is able to be loaded by this class
virtual bool isALoadableFileExtension(const c8* fileName) const; //! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const c8* fileName)const;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed. //! creates/loads an animated mesh from the file.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! \return Pointer to the created mesh. Returns 0 if loading failed.
//! See IUnknown::drop() for more information. //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
virtual scene::IAnimatedMesh* createMesh(irr::io::IReadFile* file); //! See IUnknown::drop() for more information.
private: virtual scene::IAnimatedMesh* createMesh(irr::io::IReadFile* file);
private:
struct ModelHeader {
c8 id[4]; struct ModelHeader {
u8 version[4]; c8 id[4];
u32 nameLength; u8 version[4];
u32 nameOfs; u32 nameLength;
u32 type; u32 nameOfs;
u32 type;
u32 nGlobalSequences;
u32 ofsGlobalSequences; u32 nGlobalSequences;
u32 nAnimations; u32 ofsGlobalSequences;
u32 ofsAnimations; u32 nAnimations;
u32 nC; u32 ofsAnimations;
u32 ofsC; u32 nC;
u32 nD; u32 ofsC;
u32 ofsD; u32 nD;
u32 nBones; u32 ofsD;
u32 ofsBones; u32 nBones;
u32 nF; u32 ofsBones;
u32 ofsF; u32 nF;
u32 ofsF;
u32 nVertices;
u32 ofsVertices; u32 nVertices;
u32 nViews; u32 ofsVertices;
u32 ofsViews; u32 nViews;
u32 ofsViews;
u32 nColors;
u32 ofsColors; u32 nColors;
u32 ofsColors;
u32 nTextures;
u32 ofsTextures; u32 nTextures;
u32 ofsTextures;
u32 nTransparency; // H
u32 ofsTransparency; u32 nTransparency; // H
u32 nI; // always unused ? u32 ofsTransparency;
u32 ofsI; u32 nI; // always unused ?
u32 nTexAnims; // J u32 ofsI;
u32 ofsTexAnims; u32 nTexAnims; // J
u32 nTexReplace; u32 ofsTexAnims;
u32 ofsTexReplace; u32 nTexReplace;
u32 ofsTexReplace;
u32 nTexFlags;
u32 ofsTexFlags; u32 nTexFlags;
u32 nY; u32 ofsTexFlags;
u32 ofsY; u32 nY;
u32 ofsY;
u32 nTexLookup;
u32 ofsTexLookup; u32 nTexLookup;
u32 ofsTexLookup;
u32 nTexUnitLookup; // L
u32 ofsTexUnitLookup; u32 nTexUnitLookup; // L
u32 nTransparencyLookup; // M u32 ofsTexUnitLookup;
u32 ofsTransparencyLookup; u32 nTransparencyLookup; // M
u32 nTexAnimLookup; u32 ofsTransparencyLookup;
u32 ofsTexAnimLookup; u32 nTexAnimLookup;
u32 ofsTexAnimLookup;
f32 floats[14];
f32 floats[14];
u32 nBoundingTriangles;
u32 ofsBoundingTriangles; u32 nBoundingTriangles;
u32 nBoundingVertices; u32 ofsBoundingTriangles;
u32 ofsBoundingVertices; u32 nBoundingVertices;
u32 nBoundingNormals; u32 ofsBoundingVertices;
u32 ofsBoundingNormals; u32 nBoundingNormals;
u32 ofsBoundingNormals;
u32 nAttachments; // O
u32 ofsAttachments; u32 nAttachments; // O
u32 nAttachLookup; // P u32 ofsAttachments;
u32 ofsAttachLookup; u32 nAttachLookup; // P
u32 nQ; // Q u32 ofsAttachLookup;
u32 ofsQ; u32 nQ; // Q
u32 nLights; // R u32 ofsQ;
u32 ofsLights; u32 nLights; // R
u32 nCameras; // S u32 ofsLights;
u32 ofsCameras; u32 nCameras; // S
u32 nT; u32 ofsCameras;
u32 ofsT; u32 nT;
u32 nRibbonEmitters; // U u32 ofsT;
u32 ofsRibbonEmitters; u32 nRibbonEmitters; // U
u32 nParticleEmitters; // V u32 ofsRibbonEmitters;
u32 ofsParticleEmitters; u32 nParticleEmitters; // V
u32 ofsParticleEmitters;
} header;
} header;
struct ModelVertex {
core::vector3df pos;//Use Irrlicht Vector here! struct ModelVertex {
u8 weights[4]; core::vector3df pos;//Use Irrlicht Vector here!
u8 bones[4]; u8 weights[4];
core::vector3df normal;//Use Irrlicht Vector here! u8 bones[4];
core::vector2df texcoords;//Use Irrlicht Vector here! core::vector3df normal;//Use Irrlicht Vector here!
u32 unk1, unk2; // always 0,0 so this is probably unused core::vector2df texcoords;//Use Irrlicht Vector here!
}; u32 unk1, unk2; // always 0,0 so this is probably unused
};
struct ModelView {
u32 nIndex, ofsIndex; // Vertices in this model (index into vertices[]) struct ModelView {
u32 nTris, ofsTris; // indices u32 nIndex, ofsIndex; // Vertices in this model (index into vertices[])
u32 nProps, ofsProps; // additional vtx properties u32 nTris, ofsTris; // indices
u32 nSub, ofsSub; // materials/renderops/submeshes u32 nProps, ofsProps; // additional vtx properties
u32 nTex, ofsTex; // material properties/textures u32 nSub, ofsSub; // materials/renderops/submeshes
s32 lod; // LOD bias? u32 nTex, ofsTex; // material properties/textures
}; s32 lod; // LOD bias?
};
// io::IFileSystem* FileSystem;
IrrlichtDevice* Device; struct ModelViewSubmesh {
// scene::IMeshManipulator* Manipulator; u32 meshpartId;
core::stringc M2MeshName; u16 ofsVertex;//Starting vertex number for this submesh
SAnimatedMesh* aniMesh; u16 nVertex;
SMesh* Mesh; u16 ofsTris;//Starting Triangle index
//Taken from the Model file, thus m2M* u16 nTris;
core::array<ModelVertex> M2MVertices; u16 unk1, unk2, unk3, unk4;
core::array<ModelView> M2MViews; core::vector3df v;
core::array<u16> M2MIndices; float unkf[4];
core::array<u16> M2MTriangles; };
//Used for the Mesh, thus m2_noM_*
core::array<video::S3DVertex> M2Vertices; struct TextureDefinition {
core::array<u16> M2Indices; u32 texType;
u16 unk;
}; u16 texFlags;
}//namespace scene u32 texFileLen;
}//namespace irr u32 texFileOfs;
};
struct TextureUnit{
u16 Flags;
s16 renderOrder;
u16 submeshIndex1, submeshIndex2;
s16 colorIndex;
u16 renderFlagsIndex;
u16 TextureUnitNumber;
u16 unk1;
u16 textureIndex;
u16 TextureUnitNumber2;
u16 transparencyIndex;
u16 texAnimIndex;
};
struct RenderFlags{
u16 flags;
u16 blending;
};
//
io::IFileSystem* FileSystem;
IrrlichtDevice* Device;
// scene::IMeshManipulator* Manipulator;
core::stringc M2MeshName;
core::stringc Basedir;
SAnimatedMesh* aniMesh;
SMesh* Mesh;
SMeshBuffer* IMB;
//Taken from the Model file, thus m2M*
core::array<ModelVertex> M2MVertices;
core::array<ModelView> M2MViews;
core::array<u16> M2MIndices;
core::array<u16> M2MTriangles;
core::array<ModelViewSubmesh> M2MSubmeshes;
core::array<u16> M2MTextureLookup;
core::array<TextureDefinition> M2MTextureDef;
core::array<std::string> M2MTextureFiles;
core::array<TextureUnit> M2MTextureUnit;
core::array<RenderFlags> M2MRenderFlags;
//Used for the Mesh, thus m2_noM_*
core::array<video::S3DVertex> M2Vertices;
core::array<u16> M2Indices;
};
}//namespace scene
}//namespace irr