void FW::printMemStats(void) { #if FW_MEM_DEBUG // Create snapshot of the alloc list. s_lock.enter(); AllocHeader* first = NULL; for (AllocHeader* src = s_memAllocs.next; src != &s_memAllocs; src = src->next) { AllocHeader* alloc = (AllocHeader*)::malloc(sizeof(AllocHeader)); *alloc = *src; alloc->next = first; first = alloc; } s_lock.leave(); // Calculate total size per owner. Hash<String, S64> owners; for (AllocHeader* alloc = first; alloc;) { if (!owners.contains(alloc->ownerID)) owners.add(alloc->ownerID, 0); owners[alloc->ownerID] += alloc->size; AllocHeader* next = alloc->next; ::free(alloc); alloc = next; } // Print. printf("\n"); printf("%-32s%.2f\n", "Memory usage / megs", (F32)s_memoryUsed * exp2(-20)); for (int slot = owners.firstSlot(); slot != -1; slot = owners.nextSlot(slot)) { const HashEntry<String, S64>& entry = owners.getSlot(slot); printf(" %-30s%-12.2f%.0f%%\n", entry.key.getPtr(), (F32)entry.value * exp2(-20), (F32)entry.value / (F32)s_memoryUsed * 100.0f); } printf("\n"); #endif }
void FW::exportWavefrontMesh(BufferedOutputStream& stream, const MeshBase* mesh, const String& fileName) { FW_ASSERT(mesh); Mesh<VertexPNT> pnt(*mesh); // Extract base name. String dirName = fileName.getDirName(); String baseName = fileName.getFileName(); int idx = baseName.indexOf('.'); if (idx != -1) baseName = baseName.substring(0, idx); // Write OBJ file. if (baseName.getLength()) { stream.writef("mtllib %s.mtl\n", baseName.getPtr()); stream.writef("\n"); } for (int i = 0; i < pnt.numVertices(); i++) { const VertexPNT& v = pnt.vertex(i); stream.writef("v %g %g %g\n", v.p.x, v.p.y, v.p.z); } stream.writef("\n"); for (int i = 0; i < pnt.numVertices(); i++) { const VertexPNT& v = pnt.vertex(i); stream.writef("vt %g %g\n", v.t.x, 1.0f - v.t.y); } stream.writef("\n"); for (int i = 0; i < pnt.numVertices(); i++) { const VertexPNT& v = pnt.vertex(i); stream.writef("vn %g %g %g\n", v.n.x, v.n.y, v.n.z); } for (int i = 0; i < pnt.numSubmeshes(); i++) { stream.writef("\n"); if (baseName.getLength()) stream.writef("usemtl %d\n", i); const Array<Vec3i>& tris = pnt.indices(i); for (int j = 0; j < tris.getSize(); j++) { Vec3i v = tris[j] + 1; stream.writef("f %d/%d/%d %d/%d/%d %d/%d/%d\n", v.x, v.x, v.x, v.y, v.y, v.y, v.z, v.z, v.z); } } // No base name => do not write materials. if (!baseName.getLength()) return; // Hash textures and determine file names. Hash<const Image*, String> texImageHash; Set<String> texNameSet; for (int i = 0; i < pnt.numSubmeshes(); i++) { const MeshBase::Material& mat = pnt.material(i); for (int j = 0; j < MeshBase::TextureType_Max; j++) { const Texture& tex = mat.textures[j]; if (!tex.exists() || texImageHash.contains(tex.getImage())) continue; // Extract name from ID. String name = tex.getID().getFileName(); int idx = name.indexOf('.'); if (idx != -1) name = name.substring(0, idx); // No name => generate one. if (!name.getLength()) name = sprintf("tex%d", texImageHash.getSize()); // Ensure that the name is unique. String oldName = name; for (int k = 0; texNameSet.contains(name); k++) name = sprintf("%s_%d", oldName.getPtr(), k); // Append format postfix. name += ".png"; // Record. texImageHash.add(tex.getImage(), name); texNameSet.add(name); } } // Write MTL file. File mtlFile(dirName + '/' + baseName + ".mtl", File::Create); BufferedOutputStream mtlOut(mtlFile); for (int i = 0; i < pnt.numSubmeshes(); i++) { if (i) mtlOut.writef("\n"); const MeshBase::Material& mat = pnt.material(i); mtlOut.writef("newmtl %d\n", i); mtlOut.writef("Ka 0 0 0\n"); mtlOut.writef("Kd %g %g %g\n", mat.diffuse.x, mat.diffuse.y, mat.diffuse.z); mtlOut.writef("d %g\n", mat.diffuse.w); mtlOut.writef("Ks %g %g %g\n", mat.specular.x, mat.specular.y, mat.specular.z); mtlOut.writef("Ns %g\n", mat.glossiness); if (texImageHash.contains(mat.textures[MeshBase::TextureType_Diffuse].getImage())) mtlOut.writef("map_Kd %s\n", texImageHash[mat.textures[MeshBase::TextureType_Diffuse].getImage()].getPtr()); if (texImageHash.contains(mat.textures[MeshBase::TextureType_Alpha].getImage())) mtlOut.writef("map_d %s\n", texImageHash[mat.textures[MeshBase::TextureType_Alpha].getImage()].getPtr()); if (texImageHash.contains(mat.textures[MeshBase::TextureType_Displacement].getImage())) mtlOut.writef("disp -mm %g %g %s\n", mat.displacementBias / mat.displacementCoef, mat.displacementCoef, texImageHash[mat.textures[MeshBase::TextureType_Displacement].getImage()].getPtr()); if (texImageHash.contains(mat.textures[MeshBase::TextureType_Normal].getImage())) mtlOut.writef("bump %s\n", texImageHash[mat.textures[MeshBase::TextureType_Normal].getImage()].getPtr()); if (texImageHash.contains(mat.textures[MeshBase::TextureType_Environment].getImage())) mtlOut.writef("refl -type sphere %s\n", texImageHash[mat.textures[MeshBase::TextureType_Environment].getImage()].getPtr()); } mtlOut.flush(); // Write textures. for (int i = texImageHash.firstSlot(); i != -1; i = texImageHash.nextSlot(i)) { const Image* texImage = texImageHash.getSlot(i).key; const String& texName = texImageHash.getSlot(i).value; exportImage(dirName + '/' + texName, texImage); } }