void FW::loadObj(ImportState& s, BufferedInputStream& objIn, const String& dirName) { int submesh = -1; int defaultSubmesh = -1; for (int lineNum = 1;; lineNum++) { const char* line = objIn.readLine(true, true); if (!line || ((lineNum & 0xFF) == 0 && hasError())) break; const char* ptr = line; parseSpace(ptr); bool valid = false; if (!*ptr || parseLiteral(ptr, "#")) { valid = true; } else if (parseLiteral(ptr, "v ") && parseSpace(ptr)) // position vertex { Vec3f v; if (parseFloats(ptr, v.getPtr(), 3) && parseSpace(ptr) && !*ptr) { s.positions.add(v); valid = true; } } else if (parseLiteral(ptr, "vt ") && parseSpace(ptr)) // texture vertex { Vec2f v; if (parseFloats(ptr, v.getPtr(), 2) && parseSpace(ptr)) { F32 dummy; while (parseFloat(ptr, dummy) && parseSpace(ptr)); if (!*ptr) { s.texCoords.add(Vec2f(v.x, 1.0f - v.y)); valid = true; } } } else if (parseLiteral(ptr, "vn ") && parseSpace(ptr)) // normal vertex { Vec3f v; if (parseFloats(ptr, v.getPtr(), 3) && parseSpace(ptr) && !*ptr) { s.normals.add(v); valid = true; } } else if (parseLiteral(ptr, "f ") && parseSpace(ptr)) // face { s.vertexTmp.clear(); while (*ptr) { Vec3i ptn; if (!parseInt(ptr, ptn.x)) break; for (int i = 1; i < 4 && parseLiteral(ptr, "/"); i++) { S32 tmp = 0; parseInt(ptr, tmp); if (i < 3) ptn[i] = tmp; } parseSpace(ptr); Vec3i size(s.positions.getSize(), s.texCoords.getSize(), s.normals.getSize()); for (int i = 0; i < 3; i++) { if (ptn[i] < 0) ptn[i] += size[i]; else ptn[i]--; if (ptn[i] < 0 || ptn[i] >= size[i]) ptn[i] = -1; } S32* idx = s.vertexHash.search(ptn); if (idx) s.vertexTmp.add(*idx); else { s.vertexTmp.add(s.vertexHash.add(ptn, s.mesh->numVertices())); VertexPNT& v = s.mesh->addVertex(); v.p = (ptn.x == -1) ? Vec3f(0.0f) : s.positions[ptn.x]; v.t = (ptn.y == -1) ? Vec2f(0.0f) : s.texCoords[ptn.y]; v.n = (ptn.z == -1) ? Vec3f(0.0f) : s.normals[ptn.z]; } } if (!*ptr) { if (submesh == -1) { if (defaultSubmesh == -1) defaultSubmesh = s.mesh->addSubmesh(); submesh = defaultSubmesh; } for (int i = 2; i < s.vertexTmp.getSize(); i++) s.indexTmp.add(Vec3i(s.vertexTmp[0], s.vertexTmp[i - 1], s.vertexTmp[i])); valid = true; } } else if (parseLiteral(ptr, "usemtl ") && parseSpace(ptr)) // material name { Material* mat = s.materialHash.search(ptr); if (submesh != -1) { s.mesh->mutableIndices(submesh).add(s.indexTmp); s.indexTmp.clear(); submesh = -1; } if (mat) { if (mat->submesh == -1) { mat->submesh = s.mesh->addSubmesh(); s.mesh->material(mat->submesh) = *mat; } submesh = mat->submesh; s.indexTmp.clear(); } valid = true; } else if (parseLiteral(ptr, "mtllib ") && parseSpace(ptr) && *ptr) // material library { if (dirName.getLength()) { if (hasError()) break; String fileName = dirName + "/" + ptr; File file(fileName, File::Read); BufferedInputStream mtlIn(file); loadMtl(s, mtlIn, fileName.getDirName()); #if (!WAVEFRONT_DEBUG) clearError(); #endif } valid = true; } else if ( parseLiteral(ptr, "vp ") || // parameter space vertex parseLiteral(ptr, "deg ") || // degree parseLiteral(ptr, "bmat ") || // basis matrix parseLiteral(ptr, "step ") || // step size parseLiteral(ptr, "cstype ") || // curve/surface type parseLiteral(ptr, "p ") || // point parseLiteral(ptr, "l ") || // line parseLiteral(ptr, "curv ") || // curve parseLiteral(ptr, "curv2 ") || // 2d curve parseLiteral(ptr, "surf ") || // surface parseLiteral(ptr, "parm ") || // curve/surface parameters parseLiteral(ptr, "trim ") || // curve/surface outer trimming loop parseLiteral(ptr, "hole ") || // curve/surface inner trimming loop parseLiteral(ptr, "scrv ") || // curve/surface special curve parseLiteral(ptr, "sp ") || // curve/surface special point parseLiteral(ptr, "end ") || // curve/surface end statement parseLiteral(ptr, "con ") || // surface connect parseLiteral(ptr, "g ") || // group name parseLiteral(ptr, "s ") || // smoothing group parseLiteral(ptr, "mg ") || // merging group parseLiteral(ptr, "o ") || // object name parseLiteral(ptr, "bevel ") || // bevel interpolation parseLiteral(ptr, "c_interp ") || // color interpolation parseLiteral(ptr, "d_interp ") || // dissolve interpolation parseLiteral(ptr, "lod ") || // level of detail parseLiteral(ptr, "shadow_obj ") || // shadow casting parseLiteral(ptr, "trace_obj ") || // ray tracing parseLiteral(ptr, "ctech ") || // curve approximation technique parseLiteral(ptr, "stech ") || // surface approximation technique parseLiteral(ptr, "g")) // ??? { valid = true; } #if WAVEFRONT_DEBUG if (!valid) setError("Invalid line %d in Wavefront OBJ: '%s'!", lineNum, line); #endif } // Flush remaining indices. if (submesh != -1) s.mesh->mutableIndices(submesh).add(s.indexTmp); }