1
2 #include "model.h"
3 #include <string.h> // memcpy
4 #include <cmath>
5 #include <fstream>
6 #include <iostream>
7 #include <sstream>
8 #include "Bullet3Common/b3Logging.h"
9
10 namespace TinyRender
11 {
Model(const char * filename)12 Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_()
13 {
14 std::ifstream in;
15 in.open(filename, std::ifstream::in);
16 if (in.fail()) return;
17 std::string line;
18 while (!in.eof())
19 {
20 std::getline(in, line);
21 std::istringstream iss(line.c_str());
22 char trash;
23 if (!line.compare(0, 2, "v "))
24 {
25 iss >> trash;
26 Vec3f v;
27 for (int i = 0; i < 3; i++) iss >> v[i];
28 verts_.push_back(v);
29 }
30 else if (!line.compare(0, 3, "vn "))
31 {
32 iss >> trash >> trash;
33 Vec3f n;
34 for (int i = 0; i < 3; i++) iss >> n[i];
35 norms_.push_back(n);
36 }
37 else if (!line.compare(0, 3, "vt "))
38 {
39 iss >> trash >> trash;
40 Vec2f uv;
41 for (int i = 0; i < 2; i++) iss >> uv[i];
42 uv_.push_back(uv);
43 }
44 else if (!line.compare(0, 2, "f "))
45 {
46 std::vector<Vec3i> f;
47 Vec3i tmp;
48 iss >> trash;
49 while (iss >> tmp[0] >> trash >> tmp[1] >> trash >> tmp[2])
50 {
51 for (int i = 0; i < 3; i++) tmp[i]--; // in wavefront obj all indices start at 1, not zero
52 f.push_back(tmp);
53 }
54 faces_.push_back(f);
55 }
56 }
57 std::cerr << "# v# " << verts_.size() << " f# " << faces_.size() << " vt# " << uv_.size() << " vn# " << norms_.size() << std::endl;
58 load_texture(filename, "_diffuse.tga", diffusemap_);
59 load_texture(filename, "_nm_tangent.tga", normalmap_);
60 load_texture(filename, "_spec.tga", specularmap_);
61 }
62
Model()63 Model::Model() : verts_(), faces_(), norms_(), uv_(), diffusemap_(), normalmap_(), specularmap_()
64 {
65 }
66
setDiffuseTextureFromData(unsigned char * textureImage,int textureWidth,int textureHeight)67 void Model::setDiffuseTextureFromData(unsigned char *textureImage, int textureWidth, int textureHeight)
68 {
69 {
70 B3_PROFILE("new TGAImage");
71 diffusemap_ = TGAImage(textureWidth, textureHeight, TGAImage::RGB);
72 }
73 TGAColor color;
74 color.bgra[3] = 255;
75
76 color.bytespp = 3;
77 {
78 B3_PROFILE("copy texels");
79 memcpy(diffusemap_.buffer(), textureImage, textureHeight * textureWidth * 3);
80 }
81 {
82 B3_PROFILE("flip_vertically");
83 diffusemap_.flip_vertically();
84 }
85 }
86
loadDiffuseTexture(const char * relativeFileName)87 void Model::loadDiffuseTexture(const char *relativeFileName)
88 {
89 diffusemap_.read_tga_file(relativeFileName);
90 }
91
reserveMemory(int numVertices,int numIndices)92 void Model::reserveMemory(int numVertices, int numIndices)
93 {
94 verts_.reserve(numVertices);
95 norms_.reserve(numVertices);
96 uv_.reserve(numVertices);
97 faces_.reserve(numIndices);
98 }
99
addVertex(float x,float y,float z,float normalX,float normalY,float normalZ,float u,float v)100 void Model::addVertex(float x, float y, float z, float normalX, float normalY, float normalZ, float u, float v)
101 {
102 verts_.push_back(Vec3f(x, y, z));
103 norms_.push_back(Vec3f(normalX, normalY, normalZ));
104 uv_.push_back(Vec2f(u, v));
105 }
addTriangle(int vertexposIndex0,int normalIndex0,int uvIndex0,int vertexposIndex1,int normalIndex1,int uvIndex1,int vertexposIndex2,int normalIndex2,int uvIndex2)106 void Model::addTriangle(int vertexposIndex0, int normalIndex0, int uvIndex0,
107 int vertexposIndex1, int normalIndex1, int uvIndex1,
108 int vertexposIndex2, int normalIndex2, int uvIndex2)
109 {
110 std::vector<Vec3i> f;
111 f.push_back(Vec3i(vertexposIndex0, normalIndex0, uvIndex0));
112 f.push_back(Vec3i(vertexposIndex1, normalIndex1, uvIndex1));
113 f.push_back(Vec3i(vertexposIndex2, normalIndex2, uvIndex2));
114 faces_.push_back(f);
115 }
116
~Model()117 Model::~Model() {}
118
nverts()119 int Model::nverts()
120 {
121 return (int)verts_.size();
122 }
123
nfaces()124 int Model::nfaces()
125 {
126 return (int)faces_.size();
127 }
128
face(int idx)129 std::vector<int> Model::face(int idx)
130 {
131 std::vector<int> face;
132 face.reserve((int)faces_[idx].size());
133 for (int i = 0; i < (int)faces_[idx].size(); i++)
134 face.push_back(faces_[idx][i][0]);
135 return face;
136 }
137
138
vert(int i)139 Vec3f Model::vert(int i)
140 {
141 return verts_[i];
142 }
143
vert(int iface,int nthvert)144 Vec3f Model::vert(int iface, int nthvert)
145 {
146 return verts_[faces_[iface][nthvert][0]];
147 }
148
load_texture(std::string filename,const char * suffix,TGAImage & img)149 void Model::load_texture(std::string filename, const char *suffix, TGAImage &img)
150 {
151 std::string texfile(filename);
152 size_t dot = texfile.find_last_of('.');
153 if (dot != std::string::npos)
154 {
155 texfile = texfile.substr(0, dot) + std::string(suffix);
156 std::cerr << "texture file " << texfile << " loading " << (img.read_tga_file(texfile.c_str()) ? "ok" : "failed") << std::endl;
157 img.flip_vertically();
158 }
159 }
160
diffuse(Vec2f uvf)161 TGAColor Model::diffuse(Vec2f uvf)
162 {
163 if (diffusemap_.get_width() && diffusemap_.get_height())
164 {
165 double val;
166 // bool repeat = true;
167 // if (repeat)
168 {
169 uvf[0] = std::modf(uvf[0], &val);
170 if (uvf[0] < 0)
171 {
172 uvf[0] = uvf[0] + 1;
173 }
174 uvf[1] = std::modf(uvf[1], &val);
175 if (uvf[1] < 0)
176 {
177 uvf[1] = uvf[1] + 1;
178 }
179 }
180 Vec2i uv(uvf[0] * diffusemap_.get_width(), uvf[1] * diffusemap_.get_height());
181 return diffusemap_.get(uv[0], uv[1]);
182 }
183 return TGAColor(255, 255, 255, 255);
184 }
185
186
normal(Vec2f uvf)187 Vec3f Model::normal(Vec2f uvf)
188 {
189 Vec2i uv(uvf[0] * normalmap_.get_width(), uvf[1] * normalmap_.get_height());
190 TGAColor c = normalmap_.get(uv[0], uv[1]);
191 Vec3f res;
192 for (int i = 0; i < 3; i++)
193 res[2 - i] = (float)c[i] / 255.f * 2.f - 1.f;
194 return res;
195 }
196
uv(int iface,int nthvert)197 Vec2f Model::uv(int iface, int nthvert)
198 {
199 return uv_[faces_[iface][nthvert][1]];
200 }
201
specular(Vec2f uvf)202 float Model::specular(Vec2f uvf)
203 {
204 if (specularmap_.get_width() && specularmap_.get_height())
205 {
206 Vec2i uv(uvf[0] * specularmap_.get_width(), uvf[1] * specularmap_.get_height());
207 return specularmap_.get(uv[0], uv[1])[0] / 1.f;
208 }
209 return 2.0;
210 }
211
normal(int iface,int nthvert)212 Vec3f Model::normal(int iface, int nthvert)
213 {
214 int idx = faces_[iface][nthvert][2];
215 return norms_[idx].normalize();
216 }
217 }
218