void FW::profilePush(const char* id) { if (!s_profileStarted) return; if (!Thread::isMain()) fail("profilePush() can only be used in the main thread!"); // Find or create token. S32 token; S32* found = s_profilePointerToToken.search(id); if (found) token = *found; else { found = s_profileStringToToken.search(id); if (found) token = *found; else { token = s_profileStringToToken.getSize(); s_profileStringToToken.add(id, token); } s_profilePointerToToken.add(id, token); } // Find or create timer. Vec2i timerKey(-1, token); if (s_profileStack.getSize()) timerKey.x = s_profileStack.getLast(); S32 timerIdx; found = s_profileTimerHash.search(timerKey); if (found) timerIdx = *found; else { timerIdx = s_profileTimers.getSize(); s_profileTimerHash.add(timerKey, timerIdx); ProfileTimer& timer = s_profileTimers.add(); timer.id = id; timer.parent = timerKey.x; if (timerKey.x != -1) s_profileTimers[timerKey.x].children.add(timerIdx); } // Push timer. if (s_profileStack.getSize() == 1) s_profileTimers[s_profileStack[0]].timer.start(); s_profileStack.add(timerIdx); if (s_profileStack.getSize() > 1) s_profileTimers[timerIdx].timer.start(); }
void FW::popMemOwner(void) { #if FW_MEM_DEBUG U32 threadID = Thread::getID(); Array<const char*>* stack = s_memOwnerStacks.search(threadID); if (stack) { stack->removeLast(); if (!stack->getSize()) { s_memOwnerStacks.remove(threadID); if (!s_memOwnerStacks.getSize()) s_memOwnerStacks.reset(); } } #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); } }