Jump to content
  • Advertisement
Sign in to follow this  
LongRunGames

parsing obj files

This topic is 574 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

#ifndef stringlistH
#define stringlistH


#include "FileHandling.h"
#include "const_vars.h"
#include <vector>
#ifndef WINDOWS_CMP
#include <android/log.h>
#endif
#include <fstream>
#include <sstream>
#include "DxcMath.h"
#include "string"
#include "stdlib.h"
#include <iostream>

#define APP_LOG2 "WNB_TXTLOG"


enum tFloatConversionRule { tFCDot, tFCcomma };

extern tFloatConversionRule FLOAT_CONVERSION;


#ifdef WINDOWS_CMP

inline float pstrtofloat(AnsiString num)
{      
	AnsiString temp = num;
	if (FLOAT_CONVERSION == tFCDot)     //English rule (floats are written as 10.25)
	temp = StringReplace(num,",",".", TReplaceFlags() << rfReplaceAll);
									 else      //Polish rule (floats are written as 10,25)
	temp = StringReplace(num,".",",", TReplaceFlags() << rfReplaceAll);


return StrToFloat(temp);
}
#endif



#ifndef WINDOWS_CMP

inline AnsiString booltostring(bool hue)
{
if (hue) return "true"; else return "false";
}

extern std::vector<AnsiString> w_nawiasie[10];


inline AnsiString IntToStr(int i)
{
	std::stringstream s; s;

	s << i;

	AnsiString converted(s.str());
	return converted;
}

inline AnsiString FloatToStr(float i)
{
	std::stringstream s; s;

	s << i;

	AnsiString converted(s.str());
	return converted;
}




inline int Pos(AnsiString sub, AnsiString str)
{
	 std::size_t found = str.find(sub,0);
	  if (found!=textObject ::npos)
		  return int(found)+1;
	  else
		  return 0;
}



inline int pstrtoint(AnsiString num)
{
return ::atoi(num.c_str());
}


inline int StrToInt(AnsiString num)
{
return ::atoi(num.c_str());
}


inline AnsiString StringReplace(AnsiString str, AnsiString substr, AnsiString with)
{
	AnsiString s = str;
while (Pos(substr, s) > 0)
{
	int pos = Pos(substr, s)-1;
	 s.erase(pos,substr.length());
	 s.insert(pos, with);
}
return s;
}


//inline float pstrtofloat(AnsiString num)

inline float pstrtofloat(AnsiString num)//
{
	AnsiString temp = num;

	if (FLOAT_CONVERSION == tFCDot)
	temp = StringReplace(num,",",".");
									 else
	temp = StringReplace(num,".",",");
return float(	::atof(temp.c_str())	);
}

//


inline AnsiString stddelete(AnsiString str, int pos, int len) //this is for textObject  only because i will call only Pos()-1 from it
{
	AnsiString s = str;
	 s.erase(pos, len);
	 return s;
}






extern AnsiString LowerCase(AnsiString str);
extern AnsiString UpperCase(AnsiString str);

inline int numberofchars(AnsiString line, AnsiString charstr)
{
AnsiString line2;
int result = 0;
line2 = line;
result = 0;

while ( Pos(LowerCase(charstr), LowerCase(line2)) > 0 )
{
	line2 = stddelete( line2, 0, Pos(LowerCase(charstr), LowerCase(line2)) + TextLength(charstr) - 1 );
result = result + 1;
}

return result;
}


inline AnsiString get_text_between2(AnsiString b1, AnsiString b2, AnsiString original_str)
{

if (Pos(b1,original_str) == 0) return original_str;
if (Pos(b2,original_str) == 0) return original_str;

//float, 2, 3); ahue ahue
AnsiString temp1 = stddelete(original_str, 0, Pos(b1,original_str) + b1.length() - 1 );
int k = Pos(b2,temp1) - 1;
AnsiString temp2 = stddelete(temp1, k, temp1.length() - k);
return temp2;
}



inline AnsiString get_before_char(AnsiString text, AnsiString sign, bool casesensitive)
{
AnsiString s = text;
AnsiString tmp;
if (casesensitive == false)
	tmp = stddelete(s,Pos(LowerCase(sign),LowerCase(s))-1,s.length()-Pos(LowerCase(sign),LowerCase(s))+1);
else
	tmp = stddelete(s,Pos(sign,s)-1,s.length()-Pos(sign,s)+1);


return tmp;
}


inline AnsiString get_after_char(AnsiString text, AnsiString sign, bool casesensitive)
{
AnsiString s = text;
AnsiString tmp;
if (casesensitive == false)
	tmp = stddelete(s,0,Pos(LowerCase(sign),LowerCase(s)));
	else
		tmp = stddelete(s,0,Pos(sign,s));


return tmp;
}



inline AnsiString get_after_char2(AnsiString text, AnsiString sign, bool casesensitive)
{
AnsiString s = text;
AnsiString tmp;
if (casesensitive == false)
	tmp = stddelete(s,0,Pos(LowerCase(sign),LowerCase(s))+sign.length()-1);
	else
		tmp = stddelete(s,0,Pos(sign,s)+sign.length()-1);


return tmp;
}




inline void get_all_in_nawias(AnsiString ainput, AnsiString aznak, int index)
{
    textObject  input = ainput;
    textObject  delimiter = aznak;


    w_nawiasie[index].clear();

    AnsiString pikok;

    std::size_t  start = 0U;
    std::size_t end = input.find(delimiter);

    while (end != textObject ::npos) {

    	pikok =  input.substr(start, end - start);
      w_nawiasie[index].push_back(pikok);

        start = end + delimiter.length();
        end = input.find(delimiter, start);
    }
  	pikok =  input.substr(start, end);
    w_nawiasie[index].push_back(pikok);

}


inline AnsiString ExtractFileName(AnsiString pikok)
{
	get_all_in_nawias(pikok,"/",0);
	return w_nawiasie[0][ w_nawiasie[0].size()-1 ];
}


inline AnsiString ExtractFilePath(AnsiString pikok)
{
	get_all_in_nawias(pikok,"/",0);
	if (w_nawiasie[0].size() <= 0) return "";
	AnsiString ahue = "";
	for (int i=0; i < w_nawiasie[0].size()-1; i++)
	ahue = ahue + w_nawiasie[0][i]+"/";

	return ahue;
}


inline AnsiString get_filename_ext(AnsiString pikok)
{
	AnsiString filename = ExtractFileName(pikok);
	return get_after_char(filename, ".", false);
}


inline AnsiString change_filename_ext(AnsiString pikok, AnsiString next) //push .extension important with dot ex. ".tga"
{
AnsiString path 	= ExtractFilePath(pikok);
AnsiString filename = ExtractFileName(pikok);
AnsiString fname	= get_before_char(filename,".", false);

return path+fname+next;

}



#ifdef WINDOWS_CMP
struct TStringList
#endif

#ifndef WINDOWS_CMP
struct TStringList
#endif
{

	int Count;
std::vector<AnsiString> Strings;


void Add(AnsiString text)
{
AnsiString p = text;
Strings.push_back(text);
	Count = Count + 1;
}

	AnsiString GetText()
	{
	AnsiString res = "";
	int i;
	for (i=0; i < Count; i++)
		res = res + Strings[i] + "\n";
	return res;
	}

	void AddLineAtPos(int atline, int atpos)
	{
		std::vector<AnsiString> tmp;
		tmp.clear();
		for (int i=0; i < atline; i++)
			tmp.push_back(Strings[i]);

		AnsiString prefix;
		AnsiString suffix;

if (Strings[atline].length() > 0)
{
		prefix = stddelete(Strings[atline], atpos, 100000);
		suffix = stddelete(Strings[atline], 0, atpos);

tmp.push_back(prefix);
tmp.push_back(suffix);
} else
{
tmp.push_back("");
tmp.push_back("");
}


		for (int i=atline+1; i < Count; i++)
			tmp.push_back(Strings[i]);

	Strings.clear();

	Count = Count + 1;
	for (int i=0; i < Count; i++)
	Strings.push_back(tmp[i]);

	tmp.clear();
	}

	void Clear()
	{
		Count = 0;
		Strings.clear();
	}


#ifdef WINDOWS_CMP
	AStringList()
#endif



#ifndef WINDOWS_CMP
	TStringList()
#endif
	{
		Clear();
	}

#ifdef WINDOWS_CMP
	~AStringList()
#endif



#ifndef WINDOWS_CMP
	~TStringList()
#endif
	{
		Clear();
	}

#define STRLST "WNB_LOG"
void LoadFromFile(AnsiString fname)
{

	std::ifstream file(fname.c_str());
	if (file.good() == false) {
file.close();
__android_log_print(ANDROID_LOG_VERBOSE, STRLST, "!Not good text file, aborting", 1+1);
return;
	}

	AnsiString str;

	Count = 0;
	if (Strings.size() > 0) Strings.clear();
//	__android_log_print(ANDROID_LOG_VERBOSE, STRLST, "!Loading file", 1+1);
	while (std::getline(file, str))
	{
		Strings.push_back(str);
		__android_log_print(ANDROID_LOG_VERBOSE, STRLST, str.c_str(), 1+1);
		Count = Count + 1;
	}

	file.close();

for (int i=0; i < Count; i++)
	{
		AnsiString str = Strings[i];
		 char lastChar = str.at( str.length() - 1 );

	if ( (lastChar == '\r') || (lastChar == '\n') )
	{
//		AnsiString p = "deleted newline: "+str;
//		__android_log_print(ANDROID_LOG_VERBOSE, APP_LOG2, p.c_str(), 1+1);

	str.erase(str.length()-1);
	Strings[i] = str;
	}
	}
}

//textObject  p;
AnsiString pc;

void SaveToFile(AnsiString fname)
{
	pc = GetText();
	std::ofstream outfile (fname.c_str(),std::ofstream::binary);
	int len = pc.length();
	char * buff = new char[ len ];
	memcpy(buff, pc.c_str(), sizeof(char) * len);
	outfile.write (buff, len);
	outfile.close();
}




};



#endif

extern void  init_string_float_conversion_rule();

inline AnsiString POINT_TO_TEXT(t3dpoint<float> p)
{
	return "X "+FloatToStr(p.x) + " Y "+FloatToStr(p.y)+" Z "+FloatToStr(p.z);
}

inline AnsiString iPOINT_TO_TEXT(t3dpoint<int> p)
{
	return "X "+IntToStr(p.x) + " Y "+IntToStr(p.y)+" Z "+IntToStr(p.z);
}




inline int booltoint(bool k)
{
	if (k) return 1; else return 0;
}

inline bool stringtobool(AnsiString hue)
{
AnsiString s = LowerCase(hue);
	if (s == "0") return false;
	if (s == "1") return true;

	if (s == "false") return false;
	if (s == "true") return true;
		return false;
}

#ifdef WINDOWS_CMP
#include "string_unit.hpp"
typedef TStringList AStringList;


inline void AddLineAtPos(TStringList * s, int atline, int atpos)
	{
	s->Strings[atline].Insert("\n", atpos);
	}
#endif

#endif



#include "stringlist.h"
#include <algorithm>    // std::transform

tFloatConversionRule FLOAT_CONVERSION;


void  init_string_float_conversion_rule()
{
AnsiString f;
float p = 10.250f;
f = FloatToStr(p);
#ifndef WINDOWS_CMP
if (Pos(".",f) > 0)
#endif

#ifdef WINDOWS_CMP
if (WinPosRx(".",f) > 0)
#endif
FLOAT_CONVERSION = tFCDot; else FLOAT_CONVERSION = tFCcomma;

}
#ifndef WINDOWS_CMP

std::vector<AnsiString> w_nawiasie[10];

AnsiString LowerCase(AnsiString str)
{
	AnsiString s = str;
	std::transform(s.begin(), s.end(), s.begin(), ::tolower);
return s;
}

AnsiString UpperCase(AnsiString str)
{
	AnsiString s = str;
	std::transform(s.begin(), s.end(), s.begin(), ::toupper);
return s;
}


#endif





--------------------------------------------------------------------------------------------





inline t3dpoint<float> OBJ_LINE_TO_T3dPOINT(AnsiString s)
{
t3dpoint<float> result;


get_all_in_nawias(s, " ",4);
result.x = pstrtofloat(w_nawiasie[4][1]);
result.y = pstrtofloat(w_nawiasie[4][2]);
result.z = pstrtofloat(w_nawiasie[4][3]);
//ShowMessage(showmsg3flt(result));


return result;
}




inline textpoint OBJ_LINE_TO_TEXTPOINT(AnsiString s)
{
textpoint result;

get_all_in_nawias(s, " ",4);
result.x = pstrtofloat(w_nawiasie[4][1]);
result.y = pstrtofloat(w_nawiasie[4][2]);

return result;
}



void LoadFromOBJfile(AnsiString filename, bool aloadUV, bool aloadN)
{
int vcnt = 0;
int fcnt = 0;

bool loadUV = aloadUV;
bool loadN  = aloadN;
int i;


TStringList * k = new TStringList();

TStringList * obj = new TStringList();


TStringList * VE = new TStringList();
TStringList * VT = new TStringList();
TStringList * VN = new TStringList();
		 AnsiString s;
	k->LoadFromFile(filename);
	   int r;
	   for (r = 0; r < k->Count; r++) {
	 s = k->Strings[r];
		  if ( (Pos("v ",LowerCase(s)) > 0) && (numberofchars(s,".") == 3) )  vcnt = vcnt + 1;
		  if  (Pos("f ",LowerCase(s)) > 0)  fcnt = fcnt + 1;
//		  if  ( (Pos("usemtl",LowerCase(s)) > 0) && Pos("#",LowerCase(s)) == 0)  MATERIAL_FILE->Add("NEW_MATERIAL_ON_FACE("+IntToStr(fcnt+1)+");");

	 }

vcnt = -1;
fcnt = -1;

// POBRANIE LISTY VERTEXOW DO JEDNORODNEJ LISTY
for (r = 0; r < k->Count; r++)
{
s = k->Strings[r];


if ( (Pos("v ",LowerCase(s)) > 0) && (numberofchars(s,".") == 3) )
{
	vcnt = vcnt + 1;
VE->Add(s);
}


if  (Pos("f ",LowerCase(s)) > 0)
	 fcnt = fcnt + 1;

}


//III PASS zczytanie informacji o face'ach i przypozadkowanie z VBO_N vertexow do VBO_V




AnsiString Vertex1, TexCoord1, NormalCoord1;
AnsiString Vertex2, TexCoord2, NormalCoord2;
AnsiString Vertex3, TexCoord3, NormalCoord3;
fcnt = 0;
this->header.LENGTH = fcnt * 3; //cause they are triangles
this->AOS 			= new TTGLVertex<T,float,float>[ this->header.LENGTH ];
this->FaceLength	= fcnt;
this->Matrixarr 	= new tmatrixtype[ this->FaceLength ];
this->VBO_BE 		= new tvbofacenfo[ this->FaceLength ];
this->Textureindex  = new int[ this->FaceLength ];

for (int i=0; i < this->FaceLength; i++)	Textureindex[i] = 0;

for (r = 0; r < k->Count; r++)
{
s = k->Strings[r];

if (Pos("v ",LowerCase(s)) > 0)
VE->Add(s);

if(loadUV)
if (Pos("vt ",LowerCase(s)) > 0)
VT->Add(s);


if(loadN)
if (Pos("vn ",LowerCase(s)) > 0)
VN->Add(s);
}

if (VT->Count != VE->Count)
	loadUV = false;
if (VN->Count != VE->Count)
	loadN = false;

fcnt = -1;
vcnt = 0;
for (r = 0; r < k->Count; r++)
{
s = k->Strings[r];

if  (Pos("f ",LowerCase(s)) > 0)
{ //to jest face
	 fcnt = fcnt + 1;



get_all_in_nawias(s, " ",4);

Vertex1 = get_before_char(w_nawiasie[4][1],"/",false);
Vertex2 = get_before_char(w_nawiasie[4][2],"/",false);
Vertex3 = get_before_char(w_nawiasie[4][3],"/",false);

get_all_in_nawias(w_nawiasie[4][1], "/", 0);

TexCoord1 = get_before_char(w_nawiasie[0][1],"/",false);

NormalCoord1 = get_before_char(w_nawiasie[4][1],"/",false);
NormalCoord1 = get_before_char(w_nawiasie[4][2],"/",false);
NormalCoord1 = get_before_char(w_nawiasie[4][3],"/",false);

int a,b,c;
	   a=pstrtoint(Vertex1);
	   b=pstrtoint(Vertex2);
	   c=pstrtoint(Vertex3);


if ( (a  <= VE->Count) && (b   <= VE->Count) &&
(c   <= VE->Count) )
{

	 this->Matrixarr[fcnt] = mtTriangles;
	 this->VBO_BE[fcnt].INDEX_START = fcnt * 3;
	 this->VBO_BE[fcnt].length 		= 3;



	 this->AOS[ vcnt + 0 ].v = OBJ_LINE_TO_T3dPOINT(	VE->Strings[a-1] );
	 if(loadUV)
	 this->AOS[ vcnt + 0 ].t = OBJ_LINE_TO_TEXTPOINT(	VT->Strings[a-1] );
	 if(loadN)
	 this->AOS[ vcnt + 0 ].n = OBJ_LINE_TO_T3dPOINT(	VN->Strings[a-1] );

	 this->AOS[ vcnt + 1 ].v = OBJ_LINE_TO_T3dPOINT(	VE->Strings[b-1] );
	 if(loadUV)
	 this->AOS[ vcnt + 1 ].t = OBJ_LINE_TO_TEXTPOINT(	VT->Strings[b-1] );
	 if(loadN)
	 this->AOS[ vcnt + 1 ].n = OBJ_LINE_TO_T3dPOINT(	VN->Strings[b-1] );

	 this->AOS[ vcnt + 2 ].v = OBJ_LINE_TO_T3dPOINT(	VE->Strings[c-1] );
	 if(loadUV)
	 this->AOS[ vcnt + 2 ].t = OBJ_LINE_TO_TEXTPOINT(	VT->Strings[c-1] );
	 if(loadN)
	 this->AOS[ vcnt + 2 ].n = OBJ_LINE_TO_T3dPOINT(	VN->Strings[c-1] );
	vcnt = vcnt + 3;







}


}

}

}




Milkshape could export again obj to some simplified standard wavefront obj, so code above will import it correctly

Share this post


Link to post
Share on other sites
Advertisement

Ok so I have an algorithm that imports .obj files which works fine but it was very blocky, like my model in blender.

I applied smoothing in blender and when I imported the new .obj file into my game the vertices were mostly ok but there were some major spikes and vertices in random positions.

is there a different approach between an object file with s off and with s 1?

Graham

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!