long KRTextureKTX::getMemRequiredForSize(int max_dim) { int target_dim = max_dim; if(target_dim < m_min_lod_max_dim) target_dim = target_dim; // Determine how much memory will be consumed int width = m_header.pixelWidth; int height = m_header.pixelHeight; long memoryRequired = 0; for(std::list<KRDataBlock *>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { KRDataBlock *block = *itr; if(width <= target_dim && height <= target_dim) { memoryRequired += block->getSize(); } width = width >> 1; if(width < 1) { width = 1; } height = height >> 1; if(height < 1) { height = 1; } } return memoryRequired; }
bool KRResource::save(const std::string& path) { KRDataBlock data; if(save(data)) { return data.save(path); } else { return false; } }
bool KRBundle::save(KRDataBlock &data) { if(m_pData->getSize() > KRENGINE_KRBUNDLE_HEADER_SIZE * 2) { // Only output krbundles that contain files data.append(*m_pData); } return true; }
bool KRAnimation::save(KRDataBlock &data) { tinyxml2::XMLDocument doc; tinyxml2::XMLElement *animation_node = doc.NewElement( "animation" ); doc.InsertEndChild(animation_node); animation_node->SetAttribute("loop", m_loop ? "true" : "false"); animation_node->SetAttribute("auto_play", m_auto_play ? "true" : "false"); animation_node->SetAttribute("duration", m_duration); animation_node->SetAttribute("start_time", m_start_time); for(unordered_map<std::string, KRAnimationLayer *>::iterator itr = m_layers.begin(); itr != m_layers.end(); ++itr){ (*itr).second->saveXML(animation_node); } tinyxml2::XMLPrinter p; doc.Print(&p); data.append((void *)p.CStr(), strlen(p.CStr())+1); return true; }
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; }
bool KRMaterial::save(KRDataBlock &data) { std::stringstream stream; stream.precision(std::numeric_limits<long double>::digits10); stream.setf(std::ios::fixed,std::ios::floatfield); stream << "newmtl " << m_name; stream << "\nka " << m_ambientColor.x << " " << m_ambientColor.y << " " << m_ambientColor.z; stream << "\nkd " << m_diffuseColor.x << " " << m_diffuseColor.y << " " << m_diffuseColor.z; stream << "\nks " << m_specularColor.x << " " << m_specularColor.y << " " << m_specularColor.z; stream << "\nkr " << m_reflectionColor.x << " " << m_reflectionColor.y << " " << m_reflectionColor.z; stream << "\nTr " << m_tr; stream << "\nNs " << m_ns; if(m_ambientMap.size()) { stream << "\nmap_Ka " << m_ambientMap << ".pvr -s " << m_ambientMapScale.x << " " << m_ambientMapScale.y << " -o " << m_ambientMapOffset.x << " " << m_ambientMapOffset.y; } else { stream << "\n# map_Ka filename.pvr -s 1.0 1.0 -o 0.0 0.0"; } if(m_diffuseMap.size()) { stream << "\nmap_Kd " << m_diffuseMap << ".pvr -s " << m_diffuseMapScale.x << " " << m_diffuseMapScale.y << " -o " << m_diffuseMapOffset.x << " " << m_diffuseMapOffset.y; } else { stream << "\n# map_Kd filename.pvr -s 1.0 1.0 -o 0.0 0.0"; } if(m_specularMap.size()) { stream << "\nmap_Ks " << m_specularMap << ".pvr -s " << m_specularMapScale.x << " " << m_specularMapScale.y << " -o " << m_specularMapOffset.x << " " << m_specularMapOffset.y << "\n"; } else { stream << "\n# map_Ks filename.pvr -s 1.0 1.0 -o 0.0 0.0"; } if(m_normalMap.size()) { stream << "\nmap_Normal " << m_normalMap << ".pvr -s " << m_normalMapScale.x << " " << m_normalMapScale.y << " -o " << m_normalMapOffset.x << " " << m_normalMapOffset.y; } else { stream << "\n# map_Normal filename.pvr -s 1.0 1.0 -o 0.0 0.0"; } if(m_reflectionMap.size()) { stream << "\nmap_Reflection " << m_reflectionMap << ".pvr -s " << m_reflectionMapScale.x << " " << m_reflectionMapScale.y << " -o " << m_reflectionMapOffset.x << " " << m_reflectionMapOffset.y; } else { stream << "\n# map_Reflection filename.pvr -s 1.0 1.0 -o 0.0 0.0"; } if(m_reflectionCube.size()) { stream << "\nmap_ReflectionCube " << m_reflectionCube << ".pvr"; } else { stream << "\n# map_ReflectionCube cubemapname"; } switch(m_alpha_mode) { case KRMATERIAL_ALPHA_MODE_OPAQUE: stream << "\nalpha_mode opaque"; break; case KRMATERIAL_ALPHA_MODE_TEST: stream << "\nalpha_mode test"; break; case KRMATERIAL_ALPHA_MODE_BLENDONESIDE: stream << "\nalpha_mode blendoneside"; break; case KRMATERIAL_ALPHA_MODE_BLENDTWOSIDE: stream << "\nalpha_mode blendtwoside"; break; } stream << "\n# alpha_mode opaque, test, blendoneside, or blendtwoside"; stream << "\n"; data.append(stream.str()); return true; }