Last night i made some improvements to the CMY3DMeshLoade, in the createMesh function.
Here the source.
You can just copy/paste it into you project.
Code: Select all
//--------------------------------------------------------------------------------
IAnimatedMesh* CMY3DMeshFileLoader::createMesh(
io::IReadFile* file
)
{
core::stringc file_name = file->getFileName();
// working directory (from wich we loadinfd the scene)
core::extractFilePath((c8*)file_name.c_str(), (c8*)WorkDir, 255);
core::stringc msg="";
msg="Loading scene from ";
msg.append(file_name);
logger->log(msg.c_str(), ELL_INFORMATION);
// read file into memory
file->seek(0);
u16 id;
c8 name[256];
SMyFileHeader fileHeader;
file->read(&fileHeader, sizeof(SMyFileHeader));
if (fileHeader.MyId!=MY_ID || fileHeader.Ver!=MY_VER)
{ logger->log("Bad MY3D file header, loading failed!", ELL_ERROR);
return 0;
}
file->read(&id, sizeof(id));
if (id!=MY_SCENE_HEADER_ID)
{ logger->log("Can not find MY_SCENE_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMySceneHeader sceneHeader;
file->read(&sceneHeader, sizeof(SMySceneHeader));
SceneBackgrColor = video::SColor(
sceneHeader.BackgrColor.R, sceneHeader.BackgrColor.G,
sceneHeader.BackgrColor.B, sceneHeader.BackgrColor.A
);
SceneAmbientColor = video::SColor(
sceneHeader.AmbientColor.R, sceneHeader.AmbientColor.G,
sceneHeader.AmbientColor.B, sceneHeader.AmbientColor.A
);
file->read(&id, sizeof(id));
if (id!=MY_MAT_LIST_ID)
{ logger->log("Can not find MY_MAT_LIST_ID, loading failed!", ELL_ERROR);
return 0;
}
// loading materials and textures
logger->log("Loading materials and textures...", ELL_INFORMATION);
file->read(&id, sizeof(id));
for (int m=0; m<sceneHeader.MaterialCount; m++)
{ if (id!=MY_MAT_HEADER_ID)
{ logger->log("Can not find MY_MAT_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMyMaterialEntry me;
// read material header
SMyMaterialHeader materialHeader;
file->read(&materialHeader, sizeof(SMyMaterialHeader));
me.Header = materialHeader;
// read next identificator
file->read(&id, sizeof(id));
static int LightMapIndex=0;
bool GetLightMap=false, GetMainMap=false;
for (int t=0; t<materialHeader.TextureCount; t++)
{
if (id==MY_TEX_FNAME_ID)
file->read(name, 256);
else
{
file->read(&id, sizeof(id));
if (id!=MY_TEXDATA_HEADER_ID)
{ logger->log("Can not find MY_TEXDATA_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMyTexDataHeader texDataHeader;
file->read(&texDataHeader, sizeof(SMyTexDataHeader));
core::strcpy(texDataHeader.Name, name);
char LightMapName[255];
sprintf(LightMapName,"My3D.Lightmap.%d",++LightMapIndex);
core::stringc pixFormatStr;
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
{
pixFormatStr = "24bit,";
}
else if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_16)
{
pixFormatStr = "16bit,";
}
else
{
msg="Unknown format of image data (";
msg.append(LightMapName);
msg.append("), loading failed!");
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
core::stringc comprStr ="";
if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_NONE_ID)
// none compressed image data
{
comprStr = " without compression";
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_RLE_ID)
// RLE compressed image data
{
comprStr = " RLE compression";
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_SIMPLE_ID)
// simple compressed image data
{
comprStr = " simple compression";
}
else
{
logger->log("Unknown method of compression image data, loading failed!", ELL_ERROR);
return 0;
}
c8 resStr[255];
sprintf(resStr, " %dx%d,", texDataHeader.Width, texDataHeader.Height);
msg = "Creating lightmap ";
msg.append(LightMapName);
msg.append(" (");
msg.append(pixFormatStr); msg.append(resStr); msg.append(comprStr);
msg.append(")...");
logger->log(msg.c_str(), ELL_INFORMATION);
s32 num_pixels = texDataHeader.Width*texDataHeader.Height;
void* data = 0;
if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_NONE_ID)
// none compressed image data
{
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
{ data = (void*) new SMyPixelColor24[num_pixels];
file->read(data, sizeof(SMyPixelColor24)*num_pixels);
}
else
{ data = (void*) new SMyPixelColor16[num_pixels];
file->read(data, sizeof(SMyPixelColor16)*num_pixels);
}
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_RLE_ID)
{
// read RLE header identificator
file->read(&id, sizeof(id));
if (id!=MY_TEXDATA_RLE_HEADER_ID)
{ logger->log("Can not find MY_TEXDATA_RLE_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
// read RLE header
SMyRLEHeader rleHeader;
file->read(&rleHeader, sizeof(SMyRLEHeader));
//allocate memory for input and output buffers
void *input_buffer = (void*) new unsigned char[rleHeader.nEncodedBytes];
void *output_buffer = (void*) new unsigned char[rleHeader.nDecodedBytes];
// read encoded data
file->read(input_buffer, rleHeader.nEncodedBytes);
// decode data
data = (void*) new unsigned char[rleHeader.nDecodedBytes];
s32 decodedBytes = core::rle_decode(
(unsigned char*)input_buffer, rleHeader.nEncodedBytes,
(unsigned char*)output_buffer, rleHeader.nDecodedBytes
);
if (decodedBytes!=(s32)rleHeader.nDecodedBytes)
{ logger->log("Error extracting data from RLE compression, loading failed!", ELL_ERROR);
return 0;
}
// free input buffer
delete []input_buffer;
// here decoded data
data = output_buffer;
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_SIMPLE_ID)
// simple compressed image data
{
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
data = (void*) new SMyPixelColor24[num_pixels];
else
data = (void*) new SMyPixelColor16[num_pixels];
u32 nReadedPixels =0, nToRead =0;
while (true)
{
file->read(&nToRead, sizeof(nToRead));
if ((s32)(nReadedPixels+nToRead)>(s32)num_pixels) break;
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
{ SMyPixelColor24 col24;
file->read(&col24, sizeof(SMyPixelColor24));
for (u32 p=0; p<nToRead; p++)
{ ((SMyPixelColor24*)data)[nReadedPixels+p] =
SMyPixelColor24(col24.r, col24.g, col24.b);
}
}
else
{ SMyPixelColor16 col16;
file->read(&col16, sizeof(SMyPixelColor16));
for (u32 p=0; p<nToRead; p++)
{ ((SMyPixelColor16*)data)[nReadedPixels+p].argb = col16.argb;
}
}
nReadedPixels+=nToRead;
if ((s32)nReadedPixels>=(s32)num_pixels) break;
}
if ((s32)nReadedPixels!=(s32)num_pixels)
{
logger->log("Image data seems to be corrupted, loading failed!", ELL_ERROR);
return 0;
}
}
//! Creates a software image from a byte array.
video::IImage* light_img = 0;
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
// 24 bit lightmap format
{
light_img = Driver->createImageFromData(
video::ECF_R8G8B8,
core::dimension2d<s32>(texDataHeader.Width, texDataHeader.Height),
data
);
}else
// 16 bit lightmap format
{
light_img = Driver->createImageFromData(
video::ECF_A1R5G5B5,
core::dimension2d<s32>(texDataHeader.Width, texDataHeader.Height),
data
);
}
me.LigtmapTex = Driver->addTexture(LightMapName, light_img);
//light_img->drop();
GetLightMap=true;
}
core::stringc Name = name;
int pos2 = Name.findLast('.');
core::stringc LightingMapStr = "LightingMap";
int ls = LightingMapStr.size();
core::stringc sub = Name.subString((s32)core::fmax((f32)0, (f32)(pos2 - ls)), ls);
core::stringc texFName = WorkDir;
if (sub == LightingMapStr && !GetLightMap)
{
texFName.append("Lightmaps/");
texFName.append(Name);
me.LigtmapFileName = texFName;
if (texFName!="null")
me.LigtmapTex = Driver->getTexture(texFName.c_str());
GetLightMap = true;
}
else if (!GetMainMap && !GetLightMap )
{
texFName.append(Name);
me.DiffuseTexFileName = texFName;
if (texFName!="null")
me.DiffuseTex = Driver->getTexture(texFName.c_str());
GetMainMap = true;
}
file->read(&id, sizeof(id));
}
MaterialEntry.push_back(me);
}
// loading meshes
if (Mesh) Mesh->drop();
Mesh = new SMesh();
logger->log("Loading meshes...", ELL_INFORMATION);
if (id!=MY_MESH_LIST_ID)
{ logger->log("Can not find MY_MESH_LIST_ID, loading failed!", ELL_ERROR);
return 0;
}
file->read(&id, sizeof(id));
for (s32 mesh_id=0; mesh_id<sceneHeader.MeshCount; mesh_id++)
{
//----------------------------------------------------------------
// Warning!!! In some cases MY3D exporter uncorrectly calculates
// MeshCount (it's a problem, has to be solved) thats why
// i added this code line
if (id!=MY_MESH_HEADER_ID) break;
//----------------------------------------------------------------
if (id!=MY_MESH_HEADER_ID)
{ logger->log("Can not find MY_MESH_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMyMeshHeader meshHeader;
file->read(&meshHeader, sizeof(SMyMeshHeader));
msg = " ";
msg.append(meshHeader.Name);
logger->log(msg.c_str(), ELL_INFORMATION);
core::array <SMyVertex> Vertex;
core::array <SMyFace> Face;
core::array <SMyTVertex> TVertex1, TVertex2;
core::array <SMyFace> TFace1, TFace2;
s32 vertsNum=0;
s32 facesNum=0;
// verticies
file->read(&id, sizeof(id));
if (id!=MY_VERTS_ID)
{ logger->log("Can not find MY_VERTS_ID, loading failed!", ELL_ERROR);
return 0;
}
file->read(&vertsNum, sizeof(vertsNum));
Vertex.reallocate(vertsNum);
file->read(Vertex.pointer(), sizeof(SMyVertex)*vertsNum);
Vertex.set_used(vertsNum);
// faces
file->read(&id, sizeof(id));
if (id!=MY_FACES_ID)
{ logger->log("Can not find MY_FACES_ID, loading failed!", ELL_ERROR);
return 0;
}
file->read(&facesNum, sizeof(facesNum));
Face.reallocate(facesNum);
file->read(Face.pointer(), sizeof(SMyFace)*facesNum);
Face.set_used(facesNum);
SMyMaterialEntry* matEnt = getMaterialEntryByIndex(meshHeader.MatIndex);
if (!matEnt)
{ msg="Can not find material, attached to mesh ";
msg.append(meshHeader.Name);
msg=", loading failed!";
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
// reading texture channels
for (s32 tex=0; tex<(s32)meshHeader.TChannelCnt; tex++)
// Max 2 texture channels allowed (but in format .my3d can be more)
{ s32 tVertsNum=0, tFacesNum=0;
// reading texture coords
file->read(&id, sizeof(id));
if (id!=MY_TVERTS_ID)
{ msg="Can not find MY_TVERTS_ID (";
msg.append(tex);
msg.append("texture channel), loading failed!");
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
file->read(&tVertsNum, sizeof(tVertsNum));
if (tex==0)
// 1st texture channel
{ TVertex1.reallocate(tVertsNum);
file->read(TVertex1.pointer(), sizeof(SMyTVertex)*tVertsNum);
TVertex1.set_used(tVertsNum);
}
else if (tex==1)
// 2nd texture channel
{ TVertex2.reallocate(tVertsNum);
file->read(TVertex2.pointer(), sizeof(SMyTVertex)*tVertsNum);
TVertex2.set_used(tVertsNum);
}
else
// skip other texture channels
{ u32 pos = file->getPos();
file->seek(pos+sizeof(SMyTVertex)*tVertsNum);
}
// reading texture faces
file->read(&id, sizeof(id));
if (id!=MY_TFACES_ID)
{ msg="Can not find MY_TFACES_ID (";
msg.append(tex);
msg.append("texture channel), loading failed!");
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
file->read(&tFacesNum, sizeof(tFacesNum));
if (tex==0)
// 1st texture channel
{ TFace1.reallocate(tFacesNum);
file->read(TFace1.pointer(), sizeof(SMyFace)*tFacesNum);
TFace1.set_used(tFacesNum);
}
else if (tex==1)
// 2nd texture channel
{ TFace2.reallocate(tFacesNum);
file->read(TFace2.pointer(), sizeof(SMyFace)*tFacesNum);
TFace2.set_used(tFacesNum);
}
else
// skip other texture channels
{ u32 pos = file->getPos();
file->seek(pos+sizeof(SMyFace)*tFacesNum);
}
}
// creating geometry for the mesh
SMeshBufferLightMap* buffer = new SMeshBufferLightMap();
buffer->Material.MaterialType = video::EMT_LIGHTMAP_M2; // EMT_LIGHTMAP_M4 also possible
buffer->Material.Wireframe = false;
buffer->Material.Lighting = false;
buffer->Material.BilinearFilter = true;
if (matEnt)
{
buffer->Material.Texture1 = matEnt->DiffuseTex;
buffer->Material.Texture2 = matEnt->LigtmapTex;
}
if (!buffer->Material.Texture2)
{
buffer->Material.MaterialType = video::EMT_SOLID;
}
if (matEnt && matEnt->Header.Trasparency!=0)
{
buffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
}
int vert_ind=0;
video::S3DVertex2TCoords currentVertex;
for (int f=0; f<facesNum; f++)
{
if (matEnt)
{
video::SColor color(
matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R,
matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B
);
currentVertex.Color = color.getInterpolated(video::SColor(0,0,0,0), 1-matEnt->Header.Trasparency);
}
else
{
currentVertex.Color = video::SColor(255,255,255,255);
}
currentVertex.Pos.X = Vertex[Face[f].C].Coord.X;
currentVertex.Pos.Y = Vertex[Face[f].C].Coord.Y;
currentVertex.Pos.Z = Vertex[Face[f].C].Coord.Z;
if (meshHeader.TChannelCnt>0)
{ currentVertex.TCoords.X = TVertex1[TFace1[f].C].TCoord.X;
currentVertex.TCoords.Y = TVertex1[TFace1[f].C].TCoord.Y;
}
if (meshHeader.TChannelCnt>1)
{ currentVertex.TCoords2.X = TVertex2[TFace2[f].C].TCoord.X;
currentVertex.TCoords2.Y = TVertex2[TFace2[f].C].TCoord.Y;
}
buffer->Indices.push_back(vert_ind);
buffer->Vertices.push_back(currentVertex);
vert_ind++;
currentVertex.Pos.X = Vertex[Face[f].B].Coord.X;
currentVertex.Pos.Y = Vertex[Face[f].B].Coord.Y;
currentVertex.Pos.Z = Vertex[Face[f].B].Coord.Z;
if (meshHeader.TChannelCnt>0)
{ currentVertex.TCoords.X = TVertex1[TFace1[f].B].TCoord.X;
currentVertex.TCoords.Y = TVertex1[TFace1[f].B].TCoord.Y;
}
if (meshHeader.TChannelCnt>1)
{ currentVertex.TCoords2.X = TVertex2[TFace2[f].B].TCoord.X;
currentVertex.TCoords2.Y = TVertex2[TFace2[f].B].TCoord.Y;
}
buffer->Indices.push_back(vert_ind);
buffer->Vertices.push_back(currentVertex);
vert_ind++;
currentVertex.Pos.X = Vertex[Face[f].A].Coord.X;
currentVertex.Pos.Y = Vertex[Face[f].A].Coord.Y;
currentVertex.Pos.Z = Vertex[Face[f].A].Coord.Z;
if (meshHeader.TChannelCnt>0)
{ currentVertex.TCoords.X = TVertex1[TFace1[f].A].TCoord.X;
currentVertex.TCoords.Y = TVertex1[TFace1[f].A].TCoord.Y;
}
if (meshHeader.TChannelCnt>1)
{ currentVertex.TCoords2.X = TVertex2[TFace2[f].A].TCoord.X;
currentVertex.TCoords2.Y = TVertex2[TFace2[f].A].TCoord.Y;
}
buffer->Indices.push_back(vert_ind);
buffer->Vertices.push_back(currentVertex);
vert_ind++;
}
if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA)
{
buffer->Material.BackfaceCulling = false;
SMesh* transparentMesh = new SMesh();
transparentMesh->addMeshBuffer(buffer);
SAnimatedMesh* transpSAM = new SAnimatedMesh();
// you have to add this type in IAnimatedMesh.h
//transpSAM->Type = EAMT_MY3D;
transpSAM->addMesh(transparentMesh);
transpSAM->recalculateBoundingBox();
transparentMesh->drop();
transparentMesh = 0;
if (SceneManager)
{ SceneManager -> addOctTreeSceneNode(
((IAnimatedMesh*)transpSAM)->getMesh(0)
);
}
transpSAM->drop();
}
else
Mesh->addMeshBuffer(buffer);
buffer->drop();
file->read(&id, sizeof(id));
}
if (id==MY_FILE_END_ID)
logger->log("Loading OK", ELL_INFORMATION);
else
logger->log("Loading finished, but can not find MY_FILE_END_ID token.", ELL_WARNING);
SAnimatedMesh* am = new SAnimatedMesh();
// you have to add this type in IAnimatedMesh.h
//am->Type = EAMT_MY3D;
am->addMesh(Mesh);
am->recalculateBoundingBox();
Mesh->drop();
Mesh = 0;
msg="Scene successfully loaded from";
msg.append(file_name);
logger->log(msg.c_str(), ELL_INFORMATION);
return am;
}