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