diff --git a/LearnOpenGL/ResourceLoader.cpp b/LearnOpenGL/ResourceLoader.cpp
index 12965917254d52380380fc0a3ed3e65ee3627a37..e251f3f110979f297cd0468a2b8482c82fba5bd5 100644
--- a/LearnOpenGL/ResourceLoader.cpp
+++ b/LearnOpenGL/ResourceLoader.cpp
@@ -31,167 +31,164 @@ std::string get_extension(const std::string &filePath)
 	return filePath.substr(filePath.find_last_of(".") + 1);
 }
 
-bool openObj(const std::string fileName, std::vector<glm::vec3> &vertices, std::vector<glm::vec2> &vertexTexCoord, std::vector<glm::vec3> &vertexNormals)
+std::vector<int> tokenize_index(std::string &input, const char delim)
 {
-	vertices.clear();
-	vertexTexCoord.clear();
-	vertexNormals.clear();
+	std::vector<int> result;
+	std::string token;
+	std::stringstream ss(input);
 
-	std::ifstream ifs;
+	while (getline(ss, token, delim))
+	{
+		result.push_back(std::stoi(token));
+	}
+
+	return result;
+}
+
+glm::vec2 string_to_vec2(std::vector<std::string> &input)
+{
+	glm::vec2 result;
+
+	result.x = stof(input.at(0));
+	result.y = stof(input.at(1));
+
+	return result;
+}
+glm::vec3 string_to_vec3(std::vector<std::string> &input)
+{
+	glm::vec3 result;
+
+	result.x = stof(input.at(0));
+	result.y = stof(input.at(1));
+	result.z = stof(input.at(2));
+
+	return result;
+}
+
+int parse_lines(std::ifstream &ifs, std::vector<glm::vec3> &vertices, std::vector<glm::vec2> &vertexTexCoord, std::vector<glm::vec3> &vertexNormals)
+{
 	std::string line;
+	std::vector<std::string> tokens;
+	std::string op;
 
-	char op[3];
 	std::vector<glm::vec3> vertexIndices;
 	std::vector<glm::vec2> vertexTexCoordIndices;
 	std::vector<glm::vec3> vertexNormalIndices;
 
-	ifs.open("../Models/" + fileName);
-
-	int charPos = 0;
 	while (std::getline(ifs, line))
 	{
 		if (line[0] == NULL || line[0] == '\n' || line[0] == '#' || line[0] == '!' || line[0] == '$' || line[0] == 'o' || line[0] == 'm' || line[0] == 'u') continue;
 
-		sscanf_s(line.c_str(), "%s", op, sizeof(op));
-
-		charPos = 0;
-		if ((charPos = line.find(' ')) != std::string::npos)
-		{
-			line.erase(0, charPos + 1);
-		}
+		tokens = parse_line(line);
+		op = tokens.at(0);
+		tokens.erase(tokens.begin() + 0);
 
-		if (line[0] == ' ')
+		if (op.compare("v") == 0)
 		{
-			line.erase(0, 1);
+			vertexIndices.push_back(string_to_vec3(tokens));
 		}
-
-		if (strcmp(op, "v") == false)
+		else if (op.compare("vt") == 0)
 		{
-			glm::vec3 pos = { 0,0,0 };
-			sscanf_s(line.c_str(), "%f %f %f", &pos.x, &pos.y, &pos.z);
-			vertexIndices.push_back(pos);
+			vertexTexCoordIndices.push_back(string_to_vec2(tokens));
 		}
-		else if (strcmp(op, "vn") == false)
+		else if (op.compare("vn") == 0)
 		{
-			glm::vec3 pos = { 0,0,0 };
-			sscanf_s(line.c_str(), "%f %f %f", &pos.x, &pos.y, &pos.z);
-			vertexNormalIndices.push_back(pos);
+			vertexNormalIndices.push_back(string_to_vec3(tokens));
 		}
-		else if (strcmp(op, "vt") == false)
+		else if (op.compare("f") == 0)
 		{
-			glm::vec2 pos = { 0,0 };
-			sscanf_s(line.c_str(), "%f %f", &pos.x, &pos.y);
-			vertexTexCoordIndices.push_back(pos);
-		}
+			std::vector<int> vertexInfo;
 
-		if (strncmp(op, "f", 1) == false)
-		{
-			int vIndex = 0, uvIndex = 0, vnIndex = 0;
 			std::vector<int> faceVertexIndicies;
 			std::vector<int> faceVertexTexCoordIndicies;
 			std::vector<int> faceVertexNormalIndicies;
 
-			charPos = 0;
-			while ((charPos = line.find(' ')) != std::string::npos)
+			for (auto &elem : tokens)
 			{
-				if (line.find("//") == std::string::npos)
-				{
-					sscanf_s(line.substr(0, charPos).c_str(), "%d%*[-/]%d%*[-/]%d", &vIndex, &uvIndex, &vnIndex);
-					line.erase(0, charPos + 1);
-				}
-				else
-				{
-					uvIndex = 0;
+				vertexInfo = tokenize_index(elem, '/');
 
-					sscanf_s(line.substr(0, charPos).c_str(), "%d%*[-//]%d", &vIndex, &vnIndex);
-					line.erase(0, charPos + 1);
-				}
-
-				if (vIndex >= 1)
-				{
-					faceVertexIndicies.push_back(vIndex - 1);
-				}
-				if (uvIndex >= 1)
+				if (vertexInfo.size() == 2) // maybe not included VertexTexCoord
 				{
-					faceVertexTexCoordIndicies.push_back(uvIndex - 1);
+					faceVertexIndicies.push_back(vertexInfo.at(0) - 1);
+					faceVertexNormalIndicies.push_back(vertexInfo.at(2) - 1);
 				}
-				if (vnIndex >= 1)
+				else if (vertexInfo.size() == 3)
 				{
-					faceVertexNormalIndicies.push_back(vnIndex - 1);
+					faceVertexIndicies.push_back(vertexInfo.at(0) - 1);
+					faceVertexTexCoordIndicies.push_back(vertexInfo.at(1) - 1);
+					faceVertexNormalIndicies.push_back(vertexInfo.at(2) - 1);
 				}
 			}
 
-			if (faceVertexIndicies.size() == 3)
+			if (tokens.size() == 3)
 			{
 				vertices.push_back(vertexIndices[faceVertexIndicies[0]]);
 				vertices.push_back(vertexIndices[faceVertexIndicies[1]]);
 				vertices.push_back(vertexIndices[faceVertexIndicies[2]]);
+
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[0]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[1]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[2]]);
+
+				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[0]]);
+				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[1]]);
+				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[2]]);
 			}
-			else if (faceVertexIndicies.size() == 4)
+			else if (tokens.size() == 4) // rarely, face has 4 vertices
 			{
 				vertices.push_back(vertexIndices[faceVertexIndicies[0]]);
 				vertices.push_back(vertexIndices[faceVertexIndicies[1]]);
 				vertices.push_back(vertexIndices[faceVertexIndicies[2]]);
-
 				vertices.push_back(vertexIndices[faceVertexIndicies[0]]);
 				vertices.push_back(vertexIndices[faceVertexIndicies[2]]);
 				vertices.push_back(vertexIndices[faceVertexIndicies[3]]);
-			}
-			else
-			{
-				GLchar infoLog[512] = { 0, };
-				log_warn(infoLog, fileName + " : " + "faceVertexIndices.size() : " + std::to_string(faceVertexIndicies.size()));
-			}
 
-			if (faceVertexTexCoordIndicies.size() > 0)
-			{
-				if (faceVertexTexCoordIndicies.size() == 3)
-				{
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[0]]);
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[1]]);
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[2]]);
-				}
-				else if (faceVertexTexCoordIndicies.size() == 4)
-				{
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[0]]);
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[1]]);
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[2]]);
-
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[0]]);
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[2]]);
-					vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[3]]);
-				}
-				else
-				{
-					GLchar infoLog[512] = { 0, };
-					log_warn(infoLog, fileName + " : " + "vertexTexCoordIndices.size() : " + std::to_string(faceVertexTexCoordIndicies.size()));
-				}
-			}
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[0]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[1]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[2]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[0]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[2]]);
+				vertexTexCoord.push_back(vertexTexCoordIndices[faceVertexTexCoordIndicies[3]]);
 
-			if (faceVertexNormalIndicies.size() == 3)
-			{
-				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[0]]);
-				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[1]]);
-				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[2]]);
-			}
-			else if (faceVertexNormalIndicies.size() == 4)
-			{
 				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[0]]);
 				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[1]]);
 				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[2]]);
-
 				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[0]]);
 				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[2]]);
 				vertexNormals.push_back(vertexNormalIndices[faceVertexNormalIndicies[3]]);
 			}
-			else
-			{
-				GLchar infoLog[512] = { 0, };
-				log_warn(infoLog, fileName + " : " + "faceVertexNormalIndices.size() : " + std::to_string(faceVertexNormalIndicies.size()));
-			}
 		}
 	}
 
+	return true;
+}
+
+std::vector<std::string> parse_line(std::string &line)
+{
+	std::vector<std::string> result;
+	std::stringstream ss(line);
+	std::string token;
+
+	while (ss >> token)
+	{
+		result.push_back(token);
+	}
+
+	return result;
+}
+
+bool openObj(const std::string fileName, std::vector<glm::vec3> &vertices, std::vector<glm::vec2> &vertexTexCoord, std::vector<glm::vec3> &vertexNormals)
+{
+	vertices.clear();
+	vertexTexCoord.clear();
+	vertexNormals.clear();
+
+	std::ifstream ifs;
+
+	ifs.open("../Models/" + fileName);
+
+	parse_lines(ifs, vertices, vertexTexCoord, vertexNormals);
+
 	ifs.close();
 
 	return true;
diff --git a/LearnOpenGL/ResourceLoader.h b/LearnOpenGL/ResourceLoader.h
index 21b7fa35dd472153c3c27f5a45cafd7472e486ad..7c0308428fd141a893b5d6439e953dc08951f526 100644
--- a/LearnOpenGL/ResourceLoader.h
+++ b/LearnOpenGL/ResourceLoader.h
@@ -3,6 +3,7 @@
 #include <string>
 #include <iostream>
 #include <fstream>
+#include <sstream>
 #include <vector>
 
 #include <GL/glew.h>
@@ -31,6 +32,11 @@ public:
 };
 
 std::string get_extension(const std::string &filePath);
+std::vector<int> tokenize_index(std::string &input, const char delim);
+glm::vec2 string_to_vec2(std::vector<std::string> &input);
+glm::vec3 string_to_vec3(std::vector<std::string> &input);
+int parse_lines(std::ifstream &ifs, std::vector<glm::vec3> &vertices, std::vector<glm::vec2> &vertexTexCoord, std::vector<glm::vec3> &vertexNormals);
+std::vector<std::string> parse_line(std::string &line);
 bool openObj(const std::string fileName, std::vector<glm::vec3> &vertices, std::vector<glm::vec2> &vertexTexCoord, std::vector<glm::vec3> &vertexNormals);
 Image *load_Image(std::string fileName, int *width, int *height, int *nrChannels);
 void free_image(Image *img);
\ No newline at end of file