GLLMtlFile::GLLMtlFile(CFURLRef location) { std::string filename = GLLStringFromFileURL(location); std::ifstream stream(filename.c_str()); if (!stream) throw std::runtime_error("Could not open MTLLib file."); bool hasFirstMaterial = false; std::string materialName; Material *currentMaterial = new Material(); while(stream.good()) { std::string line; std::getline(stream, line); std::istringstream linestream(line); std::string token; linestream >> token; if (token == "newmtl") { if (!hasFirstMaterial) { // This is the first material. Just save the name. linestream >> materialName; hasFirstMaterial = true; currentMaterial->name = materialName; } else { // Old material ends here. Store it here; map copies it, so it can be overwritten now. currentMaterial->ambient[3] = currentMaterial->diffuse[3] = currentMaterial->specular[3] = 1.0f; materials[materialName] = currentMaterial; // Reset material currentMaterial = new Material(); // Save new name linestream >> materialName; currentMaterial->name = materialName; } }
GLLObjFile::GLLObjFile(CFURLRef location) { std::string filename = GLLStringFromFileURL(location); int fdes = ::open(filename.c_str(), O_RDONLY); if (fdes < 0) { throw std::runtime_error("Could not open file"); } struct stat statistics; if (fstat(fdes, &statistics) < 0) { close(fdes); throw std::runtime_error("Could not get file size"); } const char *buffer = (const char *) mmap(nullptr, statistics.st_size, PROT_READ, MAP_PRIVATE, fdes, 0); close(fdes); const char *current = buffer; const char *end = &buffer[statistics.st_size]; materialLibraryURLs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); std::string activeMaterial(""); unsigned activeMaterialStart = 0; bool hasFirstMaterial = false; while(current != end) { while (current != end && (*current == ' ' || *current == '\n' || *current == '\r')) { current++; } if (current == end) break; switch (*current) { case 'f': parseFace(current, end); break; case 'v': current += 1; switch (*current) { case 'n': // Normals current += 1; parseVector(current, end, normals, 3); break; case 't': // Tex coords current += 1; parseVector(current, end, texCoords, 2); break; case 'c': // Colors current += 1; parseVector(current, end, colors, 4); break; case ' ': // Vertex parseVector(current, end, vertices, 3); break; default: skipToEndOfLine(current, end); break; } break; case 'm': if (followsString(current, end, "mtllib")) { std::string mtllib = stringToEndOfLine(current, end); try { CFURLRef mtllibLocation = GLLCreateURLFromString(mtllib, location); CFArrayAppendValue(materialLibraryURLs, mtllibLocation); CFRelease(mtllibLocation); } catch (std::exception &e) { std::cerr << "Ignoring mtllib: " << e.what() << std::endl; } } else { skipToEndOfLine(current, end); } break; case 'u': if (followsString(current, end, "usemtl")) { if (hasFirstMaterial) { // End previous material run materialRanges.push_back(MaterialRange(activeMaterialStart, (unsigned) originalIndices.size(), activeMaterial)); } else hasFirstMaterial = true; current += 1; activeMaterial = stringToEndOfLine(current, end); activeMaterialStart = (unsigned) originalIndices.size(); } else { skipToEndOfLine(current, end); } break; case '#': // Comment default: skipToEndOfLine(current, end); break; } } munmap((void *) buffer, statistics.st_size); // Wrap up final material group materialRanges.push_back(MaterialRange(activeMaterialStart, (unsigned) originalIndices.size(), activeMaterial)); fillIndices(); }