1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
void read_OBJ(const char * filename,
std::vector<vec3d> & pos, // vertex xyz positions
std::vector<vec3d> & tex, // vertex uv(w) texture coordinates
std::vector<vec3d> & nor, // vertex normals
std::vector<std::vector<uint>> & poly_pos, // polygons with references to pos
std::vector<std::vector<uint>> & poly_tex, // polygons with references to tex
std::vector<std::vector<uint>> & poly_nor, // polygons with references to nor
std::vector<Color> & poly_col, // per polygon colors
std::vector<int> & poly_lab, // per polygon labels (cluster by OBJ groups "g")
std::string & diffuse_path, // path of the image encoding the diffuse texture component
std::string & specular_path, // path of the image encoding the specular texture component
std::string & normal_path) // path of the image encoding the normal texture component
{
setlocale(LC_NUMERIC, "en_US.UTF-8"); // makes sure "." is the decimal separator
pos.clear();
tex.clear();
nor.clear();
poly_pos.clear();
poly_tex.clear();
poly_nor.clear();
poly_col.clear();
poly_lab.clear();
diffuse_path.clear();
specular_path.clear();
normal_path.clear();
std::ifstream f(filename);
if(!f.is_open())
{
std::cerr << "ERROR : " << __FILE__ << ", line " << __LINE__ << " : read_OBJ() : couldn't open input file " << filename << std::endl;
exit(-1);
}
int fresh_label = 0;
std::map<std::string,Color> color_map;
Color curr_color = Color::WHITE(); // set WHITE as default color
bool has_per_face_color = false;
bool has_groups = false;
std::string line;
while(std::getline(f,line))
{
switch(line[0])
{
case 'v':
{
// http://stackoverflow.com/questions/16839658/printf-width-specifier-to-maintain-precision-of-floating-point-value
//
double a, b, c;
if(sscanf(line.data(), "v %lf %lf %lf", &a, &b, &c) == 3) pos.push_back(vec3d(a,b,c));
else if(sscanf(line.data(), "vt %lf %lf %lf", &a, &b, &c) == 3) tex.push_back(vec3d(a,b,c));
else if(sscanf(line.data(), "vt %lf %lf %lf", &a, &b, &c) == 2) tex.push_back(vec3d(a,b,0));
else if(sscanf(line.data(), "vn %lf %lf %lf", &a, &b, &c) == 3) nor.push_back(vec3d(a,b,c));
break;
}
case 'f':
{
line = line.substr(1,line.size()-1); // discard the 'f' letter
std::istringstream ss(line);
std::vector<uint> p_pos, p_tex, p_nor;
for(std::string sub_str; ss >> sub_str;)
{
int v_pos, v_tex, v_nor;
read_point_id(strdup(sub_str.c_str()), v_pos, v_tex, v_nor);
if (v_pos >= 0) p_pos.push_back(v_pos);
if (v_tex >= 0) p_tex.push_back(v_tex);
if (v_nor >= 0) p_nor.push_back(v_nor);
}
if (!p_tex.empty()) poly_tex.push_back(p_tex);
if (!p_nor.empty()) poly_nor.push_back(p_nor);
if (!p_pos.empty())
{
poly_pos.push_back(p_pos);
poly_col.push_back(curr_color);
}
poly_lab.push_back(fresh_label);
break;
}
case 'u':
{
char mat_c[1024];
if (sscanf(line.data(), "usemtl %s", mat_c) == 1)
{
auto query = color_map.find(std::string(mat_c));
if (query != color_map.end())
{
curr_color = query->second;
}
else std::cerr << "WARNING: could not find material: " << mat_c << std::endl;
}
break;
}
case 'm':
{
char mtu_c[1024];
if(sscanf(line.data(), "mtllib %[^\n]s", mtu_c) == 1)
{
std::string s0(filename);
std::string s1(mtu_c);
std::string s2 = get_file_path(s0) + get_file_name(s1);
// this fix shouldn't be here, but...
// https://stackoverflow.com/questions/1279779/what-is-the-difference-between-r-and-n
if(!s2.empty() && s2[s2.size()-1]=='\r')
{
s2.erase(s2.size()-1);
}
if(read_MTU(s2.c_str(), color_map, diffuse_path, specular_path, normal_path))
{
has_per_face_color = true;
}
}
break;
}
case 'g':
{
has_groups = true;
fresh_label++;
break;
}
}
}
f.close();
if(!has_per_face_color) poly_col.clear();
if(!has_groups) poly_lab.clear();
}
|