1 //----------------------------------------------------------------------------- 2 // This is free and unencumbered software released into the public domain. 3 // For the full text of the Unlicense, see the file "docs/unlicense.html". 4 // Additional Unlicense information may be found at http://unlicense.org. 5 //----------------------------------------------------------------------------- 6 #include "CIrrBMeshWriter.h" 7 #include "IWriteFile.h" 8 #include "IXMLWriter.h" 9 #include "IMesh.h" 10 #include "IAttributes.h" 11 12 namespace irr 13 { 14 namespace scene 15 { 16 //! to be included EMESH_WRITER_TYPE enum 17 u32 EMWT_IRRB_MESH = MAKE_IRR_ID('i','r','r','b'); 18 get_endianess(void)19 int get_endianess(void) // 1-big, 0-lil 20 { 21 union { 22 int i; 23 char c[sizeof(int)]; 24 } t; 25 t.i = 1; 26 return t.c[0] == 0; 27 } 28 CIrrBMeshWriter(video::IVideoDriver * driver,io::IFileSystem * fs,core::array<SCustomMaterial> * customMaterials)29 CIrrBMeshWriter::CIrrBMeshWriter(video::IVideoDriver* driver, 30 io::IFileSystem* fs, core::array<SCustomMaterial>* customMaterials) 31 : FileSystem(fs), VideoDriver(driver), CustomMaterials(customMaterials), 32 Writer(0), Version(IRRB_VERSION), 33 VMajor(IRRLICHT_VERSION_MAJOR), VMinor(IRRLICHT_VERSION_MINOR), Creator("unknown"), 34 RelativeBase("") 35 { 36 if (VideoDriver) 37 VideoDriver->grab(); 38 39 if (FileSystem) 40 FileSystem->grab(); 41 } 42 ~CIrrBMeshWriter()43 CIrrBMeshWriter::~CIrrBMeshWriter() 44 { 45 if (VideoDriver) 46 VideoDriver->drop(); 47 48 if (FileSystem) 49 FileSystem->drop(); 50 } 51 52 //! Returns the type of the mesh writer getType() const53 EMESH_WRITER_TYPE CIrrBMeshWriter::getType() const 54 { 55 return (irr::scene::EMESH_WRITER_TYPE)EMWT_IRRB_MESH; 56 } 57 58 //! writes a mesh writeMesh(io::IWriteFile * file,scene::IMesh * mesh,s32 flags)59 bool CIrrBMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) 60 { 61 bool rc = false; 62 63 if (!file) 64 return false; 65 66 Writer = file; 67 68 if (!Writer) 69 { 70 //os::Printer::log("Could not write file", file->getFileName()); 71 return false; 72 } 73 74 75 //os::Printer::log("Writing mesh", file->getFileName()); 76 77 // write IRRB MESH header 78 79 writeHeader(mesh); 80 81 // write mesh 82 // todo: check the mesh type, cast it, 83 // and add appropriate animation extensions... 84 85 rc = _writeMesh(mesh); 86 87 Writer->drop(); 88 return rc; 89 } 90 _writeStringChunk(irr::core::stringc value)91 void CIrrBMeshWriter::_writeStringChunk(irr::core::stringc value) 92 { 93 struct IrrbChunkInfo ci; 94 ci.iId = CID_STRING; 95 ci.iSize = value.size() + 1; 96 Writer->write(&ci,sizeof(ci)); 97 Writer->write(value.c_str(),ci.iSize); 98 } 99 _writeChunkInfo(u32 id,u32 size)100 u32 CIrrBMeshWriter::_writeChunkInfo(u32 id, u32 size) 101 { 102 u32 offset; 103 struct IrrbChunkInfo ci; 104 105 offset = Writer->getPos(); 106 107 ci.iId = id; 108 ci.iSize = size; 109 Writer->write(&ci,sizeof(ci)); 110 111 return offset; 112 } 113 _updateChunkSize(u32 id,u32 offset)114 void CIrrBMeshWriter::_updateChunkSize(u32 id, u32 offset) 115 { 116 struct IrrbChunkInfo ci; 117 u32 cpos=Writer->getPos(); 118 119 ci.iId = id; 120 ci.iSize = cpos - offset + sizeof(ci); 121 Writer->seek(offset); 122 Writer->write(&ci,sizeof(ci)); 123 Writer->seek(cpos); 124 } 125 addMaterial(irr::video::SMaterial & material)126 bool CIrrBMeshWriter::addMaterial(irr::video::SMaterial& material) 127 { 128 irr::video::SMaterial amat; 129 130 for(u32 i=0; i<Materials.size(); i++) 131 { 132 if(material == Materials[i]) 133 return false; 134 } 135 Materials.push_back(material); 136 return true; 137 } 138 getMaterialIndex(irr::video::SMaterial & material)139 u32 CIrrBMeshWriter::getMaterialIndex(irr::video::SMaterial& material) 140 { 141 irr::video::SMaterial amat; 142 143 for(u32 i=0; i<Materials.size(); i++) 144 { 145 if(material == Materials[i]) 146 return i; 147 } 148 return 0; 149 } 150 getMaterialName(irr::video::SMaterial & material)151 irr::core::stringc CIrrBMeshWriter::getMaterialName(irr::video::SMaterial& material) 152 { 153 irr::core::stringc result="solid"; 154 155 if((u32)material.MaterialType > sizeof(irr::video::sBuiltInMaterialTypeNames)) 156 { 157 result = irr::video::sBuiltInMaterialTypeNames[material.MaterialType]; 158 } 159 else 160 { 161 for(u32 i=0; i < CustomMaterials->size(); i++) 162 { 163 if((*CustomMaterials)[i].Type == material.MaterialType) 164 { 165 result = (*CustomMaterials)[i].Name; 166 break; 167 } 168 } 169 } 170 171 return result; 172 } 173 _writeMesh(const scene::IMesh * mesh)174 bool CIrrBMeshWriter::_writeMesh(const scene::IMesh* mesh) 175 { 176 bool rc = false; 177 u32 offset; 178 struct IrrbMeshInfo mi; 179 u32 vcount=0; 180 u32 icount=0; 181 u32 mcount=0; 182 u32* voffsets; 183 u32* ioffsets; 184 u32 bcount=0; 185 186 187 offset = _writeChunkInfo(CID_MESH,0); 188 189 bcount = mesh->getMeshBufferCount(); 190 191 voffsets = (u32*) malloc(bcount * sizeof(u32)); 192 ioffsets = (u32*) malloc(bcount * sizeof(u32)); 193 194 // 195 // count vertices, indices, & materials across all mesh buffers 196 // 197 core::aabbox3d<f32> mbb; 198 mbb.reset(0.f,0.f,0.f); 199 for (int i=0; i<(int)mesh->getMeshBufferCount(); ++i) 200 { 201 scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i); 202 buffer->recalculateBoundingBox(); 203 mbb.addInternalBox(buffer->getBoundingBox()); 204 voffsets[i] = vcount; 205 ioffsets[i] = icount; 206 vcount += buffer->getVertexCount(); 207 icount += buffer->getIndexCount(); 208 209 irr::video::SMaterial& material = buffer->getMaterial(); 210 if(addMaterial(material)) 211 ++mcount; 212 } 213 214 // 215 // write mesh info struct 216 // 217 mi.iMeshBufferCount = mesh->getMeshBufferCount(); 218 mi.iVertexCount = vcount; 219 mi.iIndexCount = icount; 220 mi.iMaterialCount = mcount; 221 mi.ibbMin.x = mbb.MinEdge.X; 222 mi.ibbMin.y = mbb.MinEdge.Y; 223 mi.ibbMin.z = mbb.MinEdge.Z; 224 mi.ibbMax.x = mbb.MaxEdge.X; 225 mi.ibbMax.y = mbb.MaxEdge.Y; 226 mi.ibbMax.z = mbb.MaxEdge.Z; 227 228 Writer->write(&mi,sizeof(mi)); 229 230 // 231 // build and write vertex & index buffers 232 // 233 u32 vbufsize,ibufsize; 234 vbufsize = sizeof(struct IrrbVertex) * vcount; 235 ibufsize = sizeof(u32) * icount; 236 237 VBuffer = (struct IrrbVertex*)malloc(vbufsize); 238 IBuffer = (u32 *)malloc(ibufsize); 239 240 updateBuffers(mesh, VBuffer, IBuffer); 241 Writer->write(VBuffer,vbufsize); 242 Writer->write(IBuffer,ibufsize); 243 244 // 245 // write materials 246 // 247 for(u32 i=0; i<Materials.size(); i++) 248 { 249 struct IrrbMaterial iMat; 250 251 struct IrrbMaterialLayer iLayer; 252 253 updateMaterial(Materials[i],iMat); 254 u32 tCount=0; 255 256 for(tCount=0;tCount < 4; tCount++) 257 { 258 irr::video::ITexture* texture = Materials[i].getTexture(tCount); 259 if(!texture) 260 break; 261 } 262 iMat.mLayerCount = tCount; 263 Writer->write(&iMat,sizeof(iMat)); 264 265 for(u8 t=0; t<tCount; t++) 266 { 267 irr::core::stringc textureName; 268 //if(VMajor == 1) 269 { 270 updateMaterialLayer(Materials[i],t,textureName,iLayer); 271 _writeStringChunk(textureName); 272 Writer->write(&iLayer,sizeof(iLayer)); 273 } 274 } 275 } 276 277 // 278 // write mesh buffers info 279 // 280 _writeChunkInfo(CID_MESHBUF,0); 281 for (int i=0; i<(int)mesh->getMeshBufferCount(); ++i) 282 { 283 scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i); 284 if (buffer) 285 { 286 287 struct IrrbMeshBufInfo mbi; 288 289 // write meshbuffer info 290 291 memset(&mbi, 0, sizeof(mbi)); 292 mbi.iVertexType = buffer->getVertexType(); 293 mbi.iVertCount = buffer->getVertexCount(); 294 mbi.iVertStart = voffsets[i]; 295 mbi.iIndexCount = buffer->getIndexCount(); 296 mbi.iIndexStart = ioffsets[i]; 297 mbi.iFaceCount = buffer->getIndexCount() / 3; 298 mbi.iMaterialIndex = getMaterialIndex(buffer->getMaterial()); 299 core::stringc mname = getMaterialName(buffer->getMaterial()); 300 strncpy(mbi.iMaterialName, mname.c_str(), sizeof(mbi.iMaterialName)-1); 301 302 //video::IMaterialRenderer* mr = VideoDriver->getMaterialRenderer(mbi.iMaterialIndex); 303 304 buffer->recalculateBoundingBox(); 305 mbb = buffer->getBoundingBox(); 306 mbi.ibbMin.x = mbb.MinEdge.X; 307 mbi.ibbMin.y = mbb.MinEdge.Y; 308 mbi.ibbMin.z = mbb.MinEdge.Z; 309 mbi.ibbMax.x = mbb.MaxEdge.X; 310 mbi.ibbMax.y = mbb.MaxEdge.Y; 311 mbi.ibbMax.z = mbb.MaxEdge.Z; 312 313 Writer->write(&mbi,sizeof(mbi)); 314 } 315 } 316 _updateChunkSize(CID_MESHBUF,offset); 317 318 _updateChunkSize(CID_MESH,offset); 319 320 free(voffsets); 321 free(VBuffer); 322 free(ioffsets); 323 free(IBuffer); 324 325 return rc; 326 } 327 328 writeHeader(const scene::IMesh * mesh)329 void CIrrBMeshWriter::writeHeader(const scene::IMesh* mesh) 330 { 331 struct IrrbHeader h; 332 memset(&h,0,sizeof(h)); 333 334 // include version is visible portion 335 sprintf(h.hSig,"irrb %d.%d",Version >> 8,Version & 0xFF); 336 *(h.hSig+strlen(h.hSig)) = 0x1a; 337 338 h.hSigCheck = MAKE_IRR_ID('i','r','r','b'); 339 h.hVersion = Version; 340 h.hFlags = (get_endianess() << 16) | (sizeof(int) * 8); 341 strcpy(h.hCreator,Creator.c_str()); 342 h.hMeshCount = 1; // 1 mesh for now, todo: add ability to include lod mesh data... 343 h.hMeshBufferCount = mesh->getMeshBufferCount(); 344 Writer->write(&h,sizeof(h)); 345 } 346 updateBuffers(const scene::IMesh * mesh,struct IrrbVertex * VBuffer,u32 * IBuffer)347 void CIrrBMeshWriter::updateBuffers(const scene::IMesh* mesh, 348 struct IrrbVertex* VBuffer,u32* IBuffer) 349 { 350 u32 vidx=0,iidx=0; 351 352 for (int i=0; i<(int)mesh->getMeshBufferCount(); ++i) 353 { 354 scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i); 355 if (buffer) 356 { 357 u32 vertexCount = buffer->getVertexCount(); 358 359 switch(buffer->getVertexType()) 360 { 361 case video::EVT_STANDARD: 362 { 363 video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices(); 364 for (u32 j=0; j<vertexCount; ++j) 365 { 366 VBuffer[vidx].vPos.x = vtx[j].Pos.X; 367 VBuffer[vidx].vPos.y = vtx[j].Pos.Y; 368 VBuffer[vidx].vPos.z = vtx[j].Pos.Z; 369 370 VBuffer[vidx].vNormal.x = vtx[j].Normal.X; 371 VBuffer[vidx].vNormal.y = vtx[j].Normal.Y; 372 VBuffer[vidx].vNormal.z = vtx[j].Normal.Z; 373 374 VBuffer[vidx].vColor = vtx[j].Color.color; 375 376 VBuffer[vidx].vUV1.x = vtx[j].TCoords.X; 377 VBuffer[vidx].vUV1.y = vtx[j].TCoords.Y; 378 ++vidx; 379 } 380 } 381 break; 382 case video::EVT_2TCOORDS: 383 { 384 video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); 385 for (u32 j=0; j<vertexCount; ++j) 386 { 387 VBuffer[vidx].vPos.x = vtx[j].Pos.X; 388 VBuffer[vidx].vPos.y = vtx[j].Pos.Y; 389 VBuffer[vidx].vPos.z = vtx[j].Pos.Z; 390 391 VBuffer[vidx].vNormal.x = vtx[j].Normal.X; 392 VBuffer[vidx].vNormal.y = vtx[j].Normal.Y; 393 VBuffer[vidx].vNormal.z = vtx[j].Normal.Z; 394 395 VBuffer[vidx].vColor = vtx[j].Color.color; 396 397 VBuffer[vidx].vUV1.x = vtx[j].TCoords.X; 398 VBuffer[vidx].vUV1.y = vtx[j].TCoords.Y; 399 VBuffer[vidx].vUV2.x = vtx[j].TCoords2.X; 400 VBuffer[vidx].vUV2.y = vtx[j].TCoords2.Y; 401 ++vidx; 402 403 } 404 } 405 break; 406 case video::EVT_TANGENTS: 407 { 408 video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices(); 409 for (u32 j=0; j<vertexCount; ++j) 410 { 411 VBuffer[vidx].vPos.x = vtx[j].Pos.X; 412 VBuffer[vidx].vPos.y = vtx[j].Pos.Y; 413 VBuffer[vidx].vPos.z = vtx[j].Pos.Z; 414 415 VBuffer[vidx].vNormal.x = vtx[j].Normal.X; 416 VBuffer[vidx].vNormal.y = vtx[j].Normal.Y; 417 VBuffer[vidx].vNormal.z = vtx[j].Normal.Z; 418 419 VBuffer[vidx].vColor = vtx[j].Color.color; 420 421 VBuffer[vidx].vUV1.x = vtx[j].TCoords.X; 422 VBuffer[vidx].vUV1.y = vtx[j].TCoords.Y; 423 424 VBuffer[vidx].vTangent.x = vtx[j].Tangent.X; 425 VBuffer[vidx].vTangent.y = vtx[j].Tangent.Y; 426 VBuffer[vidx].vTangent.z = vtx[j].Tangent.Z; 427 428 VBuffer[vidx].vBiNormal.x = vtx[j].Binormal.X; 429 VBuffer[vidx].vBiNormal.y = vtx[j].Binormal.Y; 430 VBuffer[vidx].vBiNormal.z = vtx[j].Binormal.Z; 431 ++vidx; 432 } 433 } 434 break; 435 } 436 437 // update indices 438 u32 indexCount = buffer->getIndexCount(); 439 const u16* idx16 = buffer->getIndices(); 440 const u32* idx32 = (u32 *)buffer->getIndices(); 441 442 video::E_INDEX_TYPE iType = buffer->getIndexType(); 443 444 for(u32 j=0; j<indexCount; j++) 445 { 446 if(iType == video::EIT_16BIT) 447 IBuffer[iidx++] = idx16[j]; 448 else 449 IBuffer[iidx++] = idx32[j]; 450 } 451 } 452 } 453 } 454 updateMaterialLayer(const video::SMaterial & material,u8 layerNumber,irr::core::stringc & textureName,struct IrrbMaterialLayer & layer)455 void CIrrBMeshWriter::updateMaterialLayer(const video::SMaterial& material,u8 layerNumber, irr::core::stringc& textureName, struct IrrbMaterialLayer& layer) 456 { 457 if(layerNumber > 3) 458 return; 459 460 memset(&layer,0,sizeof(layer)); 461 462 textureName = material.TextureLayer[layerNumber].Texture->getName().getPath().c_str(); 463 464 if(RelativeBase.size()) 465 { 466 // simple relative path calculation 467 int blen = RelativeBase.size(); 468 int tlen = textureName.size(); 469 int idx = 0; 470 471 const char *bp = RelativeBase.c_str(); 472 const char *tp = textureName.c_str(); 473 474 while( (idx < blen) & (idx < tlen)) 475 { 476 if(bp[idx] != tp[idx]) 477 break; 478 ++idx; 479 } 480 textureName = textureName.subString(idx, textureName.size()); 481 } 482 483 layer.mBilinearFilter = material.TextureLayer[layerNumber].BilinearFilter; 484 layer.mTrilinearFilter = material.TextureLayer[layerNumber].TrilinearFilter; 485 layer.mAnisotropicFilter = material.TextureLayer[layerNumber].AnisotropicFilter; 486 layer.mTextureWrapU = material.TextureLayer[layerNumber].TextureWrapU; 487 layer.mTextureWrapV = material.TextureLayer[layerNumber].TextureWrapV; 488 layer.mLODBias = material.TextureLayer[layerNumber].LODBias; 489 memcpy(&layer.mMatrix,material.TextureLayer[layerNumber].getTextureMatrix().pointer(),sizeof(f32)*16); 490 } 491 updateMaterial(const video::SMaterial & material,struct IrrbMaterial & mat)492 void CIrrBMeshWriter::updateMaterial(const video::SMaterial& material, struct IrrbMaterial& mat) 493 { 494 495 memset(&mat,0,sizeof(mat)); 496 497 mat.mType = material.MaterialType; 498 mat.mAmbient = material.AmbientColor.color; 499 mat.mDiffuse = material.DiffuseColor.color; 500 mat.mEmissive = material.EmissiveColor.color; 501 mat.mSpecular = material.SpecularColor.color; 502 mat.mShininess = material.Shininess; 503 mat.mParm1 = material.MaterialTypeParam; 504 mat.mParm2 = material.MaterialTypeParam2; 505 mat.mThickness = material.Thickness; 506 mat.mZBuffer = material.ZBuffer; 507 mat.mAntiAliasing = material.AntiAliasing; 508 mat.mColorMask = material.ColorMask; 509 mat.mColorMaterial = material.ColorMaterial; 510 mat.mBlendOperation = material.BlendOperation; 511 mat.mPolygonOffsetFactor = material.PolygonOffsetFactor; 512 mat.mPolygonOffsetDirection = material.PolygonOffsetDirection; 513 514 mat.mWireframe = material.Wireframe; 515 mat.mPointCloud = material.PointCloud; 516 mat.mGrouraudShading = material.GouraudShading; 517 mat.mLighting = material.Lighting; 518 mat.mZWriteEnabled = material.ZWriteEnable; 519 mat.mBackfaceCulling = material.BackfaceCulling; 520 mat.mFrontfaceCulling = material.FrontfaceCulling; 521 mat.mFogEnable = material.FogEnable; 522 mat.mNormalizeNormals = material.NormalizeNormals; 523 mat.mUseMipMaps = material.UseMipMaps; 524 } 525 } // end namespace 526 } // end namespace 527