KRMaterial::KRMaterial(KRContext &context, const char *szName) : KRResource(context, szName) { m_name = szName; m_pAmbientMap = NULL; m_pDiffuseMap = NULL; m_pSpecularMap = NULL; m_pNormalMap = NULL; m_pReflectionMap = NULL; m_pReflectionCube = NULL; m_ambientColor = KRVector3::Zero(); m_diffuseColor = KRVector3::One(); m_specularColor = KRVector3::One(); m_reflectionColor = KRVector3::Zero(); m_tr = (GLfloat)1.0f; m_ns = (GLfloat)0.0f; m_ambientMap = ""; m_diffuseMap = ""; m_specularMap = ""; m_normalMap = ""; m_reflectionMap = ""; m_reflectionCube = ""; m_ambientMapOffset = KRVector2(0.0f, 0.0f); m_specularMapOffset = KRVector2(0.0f, 0.0f); m_diffuseMapOffset = KRVector2(0.0f, 0.0f); m_ambientMapScale = KRVector2(1.0f, 1.0f); m_specularMapScale = KRVector2(1.0f, 1.0f); m_diffuseMapScale = KRVector2(1.0f, 1.0f); m_reflectionMapOffset = KRVector2(0.0f, 0.0f); m_reflectionMapScale = KRVector2(1.0f, 1.0f); m_alpha_mode = KRMATERIAL_ALPHA_MODE_OPAQUE; }
KRVector2 KRVector3::yy() const { return KRVector2(y,y); }
KRVector2 KRVector3::yx() const { return KRVector2(y,x); }
KRVector2 KRVector3::xz() const { return KRVector2(x,z); }
KRVector2 KRVector3::xy() const { return KRVector2(x,y); }
KRVector2 KRVector3::xx() const { return KRVector2(x,x); }
KRVector2 KRVector2::Max() { return KRVector2(std::numeric_limits<float>::max()); }
KRVector2 KRVector2::operator *(const float v) const { return KRVector2(x * v, y * v); }
KRVector2 KRVector2::operator /(const float v) const { float inv_v = 1.0f / v; return KRVector2(x * inv_v, y * inv_v); }
KRVector2 KRVector2::operator -(const KRVector2& b) const { return KRVector2(x - b.x, y - b.y); }
KRVector2 KRVector2::operator -() const { return KRVector2(-x, -y); }
KRVector2 KRVector2::operator +(const KRVector2& b) const { return KRVector2(x + b.x, y + b.y); }
KRVector2 KRVector2::One() { return KRVector2(1.0f); }
KRVector2 KRVector2::Zero() { return KRVector2(0.0f); }
KRVector2 KRVector3::yz() const { return KRVector2(y,z); }
KRVector2 KRVector3::zy() const { return KRVector2(z,y); }
KRVector2 KRVector3::zx() const { return KRVector2(z,x); }
KRVector2 KRVector3::zz() const { return KRVector2(z,z); }
std::vector<KRResource *> KRResource::LoadObj(KRContext &context, const std::string& path) { std::vector<KRResource *> resources; KRMesh *new_mesh = new KRMesh(context, KRResource::GetFileBase(path)); resources.push_back(new_mesh); KRMesh::mesh_info mi; std::vector<std::string> material_names_t; KRDataBlock data; char szSymbol[500][256]; int *pFaces = NULL; vector<KRMesh::pack_material *> m_materials; if(data.load(path)) { // -----=====----- Get counts -----=====----- int cVertexData = 0; int cFaces = 1; int cMaterialFaceStart = 1; char *pScan = (char *)data.getStart(); char *pEnd = (char *)data.getEnd(); while(pScan < pEnd) { // Scan through whitespace while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) { pScan++; } if(*pScan == '#') { // Line is a comment line // Scan to the end of the line while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') { pScan++; } } else { int cSymbols = 0; while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') { char *pDest = szSymbol[cSymbols++]; while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') { *pDest++ = *pScan++; } *pDest = '\0'; // Scan through whitespace, but don't advance to next line while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) { pScan++; } } if(strcmp(szSymbol[0], "v") == 0) { // Vertex (v) } else if(strcmp(szSymbol[0], "vt") == 0) { // Vertex Texture UV Coordinate (vt) } else if(strcmp(szSymbol[0], "vn") == 0) { // Vertex Normal (vn) } else if(strcmp(szSymbol[0], "f") == 0) { // Face (f) int cFaceVertexes = (cSymbols - 3) * 3; // 3 vertexes per triangle. Triangles have 4 symbols. Quads have 5 symbols and generate two triangles. cVertexData += cFaceVertexes; cFaces += cFaceVertexes * 3 + 1; // Allocate space for count of vertices, Vertex Index, Texture Coordinate Index, and Normal Index } else if(strcmp(szSymbol[0], "usemtl") == 0) { // Use Material (usemtl) if(cMaterialFaceStart - cFaces > 0) { cFaces++; } material_names_t.push_back(std::string(szSymbol[1])); } } } // -----=====----- Populate vertexes and faces -----=====----- int *pFaces = (int *)malloc(sizeof(int *) * (cFaces + 1)); assert(pFaces != NULL); std::vector<KRVector3> indexed_vertices; std::vector<KRVector2> indexed_uva; std::vector<KRVector3> indexed_normals; int *pFace = pFaces; int *pMaterialFaces = pFace++; *pMaterialFaces = 0; // -------- pScan = (char *)data.getStart(); while(pScan < pEnd) { // Scan through whitespace while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t' || *pScan == '\r' || *pScan == '\n')) { pScan++; } if(*pScan == '#') { // Line is a comment line // Scan to the end of the line while(pScan < pEnd && *pScan != '\r' && *pScan != '\n') { pScan++; } } else { int cSymbols = 0; while(pScan < pEnd && *pScan != '\n' && *pScan != '\r') { char *pDest = szSymbol[cSymbols++]; while(pScan < pEnd && *pScan != ' ' && *pScan != '\n' && *pScan != '\r') { *pDest++ = *pScan++; } *pDest = '\0'; // Scan through whitespace, but don't advance to next line while(pScan < pEnd && (*pScan == ' ' || *pScan == '\t')) { pScan++; } } if(strcmp(szSymbol[0], "v") == 0) { // Vertex (v) float x, y, z; char *pChar = szSymbol[1]; x = strtof(pChar, &pChar); pChar = szSymbol[2]; y = strtof(pChar, &pChar); pChar = szSymbol[3]; z = strtof(pChar, &pChar); indexed_vertices.push_back(KRVector3(x,y,z)); } else if(strcmp(szSymbol[0], "vt") == 0) { // Vertex Texture UV Coordinate (vt) char *pChar = szSymbol[1]; float u,v; u = strtof(pChar, &pChar); pChar = szSymbol[2]; v = strtof(pChar, &pChar); indexed_uva.push_back(KRVector2(u,v)); } else if(strcmp(szSymbol[0], "vn") == 0) { // Vertex Normal (vn) float x,y,z; char *pChar = szSymbol[1]; x = strtof(pChar, &pChar); pChar = szSymbol[2]; y = strtof(pChar, &pChar); pChar = szSymbol[3]; z = strtof(pChar, &pChar); indexed_normals.push_back(KRVector3(x,y,z)); } else if(strcmp(szSymbol[0], "f") == 0) { // Face (f) int cFaceVertices = cSymbols - 1; *pFace++ = cFaceVertices; for(int iSymbol=1; iSymbol < cSymbols; iSymbol++) { char *pChar = szSymbol[iSymbol]; if(*pChar == '.' || (*pChar >= '0' && *pChar <= '9')) { *pFace++ = strtol(pChar, &pChar, 10) - 1; // Vertex Index if(*pChar == '/') { pChar++; if(*pChar == '/') { *pFace++ = -1; } else { *pFace++ = strtol(pChar, &pChar, 10) - 1; // Texture Coordinate Index } } else { *pFace++ = -1; } if(*pChar == '/') { pChar++; if(*pChar == '/') { *pFace++ = -1; } else { *pFace++ = strtol(pChar, &pChar, 10) - 1; // Normal Index } } else { *pFace++ = -1; } while(*pChar == '/') { pChar++; strtol(pChar, &pChar, 10); } } } } else if(strcmp(szSymbol[0], "usemtl") == 0) { // Use Material (usemtl) if(pFace - pMaterialFaces > 1) { *pMaterialFaces = pFace - pMaterialFaces - 1; pMaterialFaces = pFace++; } } } } *pMaterialFaces = pFace - pMaterialFaces - 1; *pFace++ = 0; int iVertex = 0; std::vector<std::string>::iterator material_itr = material_names_t.begin(); KRMesh::pack_material *pMaterial = new KRMesh::pack_material(); pMaterial->start_vertex = iVertex; pMaterial->vertex_count = 0; memset(pMaterial->szName, 256, 0); if(material_itr < material_names_t.end()) { strncpy(pMaterial->szName, (*material_itr++).c_str(), 256); } m_materials.push_back(pMaterial); pFace = pFaces; while(*pFace != 0 && iVertex < cVertexData) { pMaterial->start_vertex = iVertex; int *pMaterialEndFace = pFace + *pFace++; while(pFace < pMaterialEndFace && iVertex < cVertexData) { int cFaceVertexes = *pFace; KRVector3 firstFaceVertex; KRVector3 prevFaceVertex; KRVector3 firstFaceNormal; KRVector3 prevFaceNormal; KRVector2 firstFaceUva; KRVector2 prevFaceUva; for(int iFaceVertex=0; iFaceVertex < cFaceVertexes; iFaceVertex++) { if(iFaceVertex > 2) { // There have already been 3 vertices. Now we need to split the quad into a second triangle composed of the 1st, 3rd, and 4th vertices iVertex+=2; mi.vertices.push_back(firstFaceVertex); mi.uva.push_back(firstFaceUva); mi.normals.push_back(firstFaceNormal); mi.vertices.push_back(prevFaceVertex); mi.uva.push_back(prevFaceUva); mi.normals.push_back(prevFaceNormal); } KRVector3 vertex = indexed_vertices[pFace[iFaceVertex*3+1]]; KRVector2 new_uva; if(pFace[iFaceVertex*3+2] >= 0) { new_uva = indexed_uva[pFace[iFaceVertex*3+2]]; } KRVector3 normal; if(pFace[iFaceVertex*3+3] >= 0){ KRVector3 normal = indexed_normals[pFace[iFaceVertex*3+3]]; } mi.vertices.push_back(vertex); mi.uva.push_back(new_uva); mi.normals.push_back(normal); if(iFaceVertex==0) { firstFaceVertex = vertex; firstFaceUva = new_uva; firstFaceNormal = normal; } prevFaceVertex = vertex; prevFaceUva = new_uva; prevFaceNormal = normal; iVertex++; } pFace += cFaceVertexes * 3 + 1; } pMaterial->vertex_count = iVertex - pMaterial->start_vertex; if(*pFace != 0) { pMaterial = new KRMesh::pack_material(); pMaterial->start_vertex = iVertex; pMaterial->vertex_count = 0; memset(pMaterial->szName, 256, 0); if(material_itr < material_names_t.end()) { strncpy(pMaterial->szName, (*material_itr++).c_str(), 256); } m_materials.push_back(pMaterial); } } for(int iMaterial=0; iMaterial < m_materials.size(); iMaterial++) { KRMesh::pack_material *pNewMaterial = m_materials[iMaterial]; if(pNewMaterial->vertex_count > 0) { mi.material_names.push_back(std::string(pNewMaterial->szName)); mi.submesh_starts.push_back(pNewMaterial->start_vertex); mi.submesh_lengths.push_back(pNewMaterial->vertex_count); } delete pNewMaterial; } // TODO: Bones not yet supported for OBJ // std::vector<std::string> bone_names; // std::vector<KRMat4> bone_bind_poses; // std::vector<std::vector<int> > bone_indexes; // std::vector<std::vector<float> > bone_weights; // // std::vector<__uint16_t> vertex_indexes; // std::vector<std::pair<int, int> > vertex_index_bases; mi.format = KRMesh::KRENGINE_MODEL_FORMAT_TRIANGLES; new_mesh->LoadData(mi, true, false); } if(pFaces) { free(pFaces); } return resources; }
KRVector2 KRVector2::Normalize(const KRVector2 &v) { float inv_magnitude = 1.0f / sqrtf(v.x * v.x + v.y * v.y); return KRVector2(v.x * inv_magnitude, v.y * inv_magnitude); }