1 /***************************************************************************
2  * Brutal Chess
3  * http://brutalchess.sf.net
4  *
5  * File : md3model.cpp
6  * Authors : Mike Cook, Joe Flint, Neil Pankey
7  **************************************************************************/
8 
9 #include "md3model.h"
10 
11 #include <iostream>
12 #include <fstream>
13 #include <sstream>
14 #include <string>
15 #include <cmath>
16 #ifndef WIN32
17 	#include <libgen.h>
18 #endif
19 
20 #include "SDL_opengl.h"
21 #include "SDL.h"
22 
23 using namespace std;
24 
load(const string & filename,const string & skin)25 bool MD3Model::load(const string& filename, const string& skin)
26 {
27 	float pi = 3.1415;
28 	m_filename = filename;
29 	m_skin = skin;
30 	ifstream infile(m_filename.c_str(), ios::in | ios::binary);
31 	if (!infile.is_open()) {
32 		cout << "Couldn't open file " << m_filename << endl;
33 		return false;
34 	}
35 
36 	infile.read((char*)&m_header, sizeof(m_header));
37 
38 	md3Frame_t	currFrame;
39 	infile.seekg(m_header.frame_start, ios_base::beg);
40 	for (int i = 0; i < m_header.frame_num; ++i) {
41 		infile.read((char*)&currFrame.header, sizeof(md3FrameHeader_t));
42 		m_frames.push_back(currFrame);
43 	}
44 
45 	md3Tag_t currTag;
46 	infile.seekg(m_header.tag_start, ios_base::beg);
47 	for (int i = 0; i < m_header.frame_num; ++i) {
48 		for (int j = 0; j < m_header.tag_num; ++j) {
49 			infile.read((char*)&currTag, sizeof(md3Tag_t));
50 			if((currTag.origin[0] >= -0.001 && currTag.origin[0] <= 0.001) &&
51 			   (currTag.origin[1] >= -0.001 && currTag.origin[1] <= 0.001) &&
52 			   (currTag.origin[2] >= -0.001 && currTag.origin[2] <= 0.001))
53 				m_tagname = currTag.name;
54 			m_frames[i].tags.push_back(currTag);
55 		}
56 	}
57 
58 	md3Mesh_t currMesh;
59 	infile.seekg(m_header.mesh_start, ios_base::beg);
60 	for(int i = 0; i < m_header.mesh_num; i++) {
61 		int headerstart = infile.tellg();
62 		currMesh.skins.clear();
63 		currMesh.triangles.clear();
64 		currMesh.texcoords.clear();
65 		currMesh.vertices.clear();
66 		infile.read((char*)&currMesh.header, sizeof(md3MeshHeader_t));
67 
68 		md3Skin_t currSkin;
69 		for(int i = 0; i < currMesh.header.skin_num; ++i) {
70 			infile.read((char*)&currSkin, sizeof(md3Skin_t));
71 			currMesh.skins.push_back(currSkin);
72 		}
73 
74 		infile.seekg(headerstart + currMesh.header.triangle_start, ios_base::beg);
75 		md3Triangle_t currTriangle;
76 		for(int i = 0; i < currMesh.header.triangle_num; ++i) {
77 			infile.read((char*)&currTriangle, sizeof(md3Triangle_t));
78 			currMesh.triangles.push_back(currTriangle);
79 		}
80 
81 		infile.seekg(headerstart + currMesh.header.texcoord_start, ios_base::beg);
82 		md3TexCoord_t currTexCoord;
83 		for(int i = 0; i < currMesh.header.vertex_num; ++i) {
84 			infile.read((char*)&currTexCoord, sizeof(md3TexCoord_t));
85 			currMesh.texcoords.push_back(currTexCoord);
86 		}
87 
88 		infile.seekg(headerstart + currMesh.header.vertex_start, ios_base::beg);
89 		md3Vertex_t currVertex;
90 		md3Normal_t currNormal;
91 		currMesh.normals.clear();
92 		for(int i = 0; i < currMesh.header.vertex_num * currMesh.header.frame_num; ++i) {
93 			infile.read((char*)&currVertex, sizeof(md3Vertex_t));
94 			currNormal.x = cos(2*pi*currVertex.normals[1]/255.0)*sin(2*pi*currVertex.normals[0]/255.0);
95 			currNormal.y = sin(2*pi*currVertex.normals[1]/255.0)*sin(2*pi*currVertex.normals[0]/255.0);
96 			currNormal.z = cos(2*pi*currVertex.normals[0]/255.0);
97 			currMesh.vertices.push_back(currVertex);
98 			currMesh.normals.push_back(currNormal);
99 		}
100 		infile.seekg(headerstart + currMesh.header.mesh_size, ios_base::beg);
101 		m_meshes.push_back(currMesh);
102 	}
103 
104 	string skinfile = m_filename.substr(0, m_filename.length() - 4);
105 	skinfile += "_" + m_skin + ".skin";
106 
107 	ifstream skininfile(skinfile.c_str(), ios::in);
108 	string in;
109 	string tok;
110 	vector<string> toks;
111 	while((skininfile >> in)) {
112 		while(in.find(',') != string::npos)
113 			in.replace(in.find(','), 1, " ");
114 		istringstream linein(in);
115 
116 		toks.clear();
117 		while((linein >> tok)) {
118 			if(tok != "")
119 				toks.push_back(tok);
120 		}
121 		if(toks.size() == 2) {
122 			for(int i = 0; i < m_header.mesh_num; i++) {
123 				char buf[1024];
124 				char* bufptr = buf;
125 				if(string(m_meshes[i].header.name) == toks[0]) {
126 					strncpy(bufptr, m_filename.c_str(), 1024);
127 #ifndef WIN32
128 					bufptr = dirname(bufptr);
129 #endif
130 					string texfile = bufptr;
131 					strncpy(buf, toks[1].c_str(), 1024);
132 #ifndef WIN32
133 					bufptr = basename(bufptr);
134 #endif
135 					texfile += "/";
136 					texfile += bufptr;
137 					if(m_textures.find(toks[1]) == m_textures.end()) {
138 						cout << "'" << toks[1] << "'" << endl;
139 						m_textures[toks[1]] = Texture();
140 						if(!m_textures[toks[1]].load(texfile))
141 							cout << "Failed to load texture: " << texfile << endl;
142 					}
143 					m_meshes[i].tex = toks[1];
144 				}
145 			}
146 		}
147 	}
148 
149 	return true;
150 }
151 
loadGL()152 bool MD3Model::loadGL()
153 {
154 	cout << "LoadGL called" << endl;
155 	for(map<string, Texture>::iterator ti = m_textures.begin(); ti != m_textures.end(); ti++) {
156 		cout << "'" << ti->first << "'" << endl;
157 		ti->second.loadGL();
158 	}
159 	return true;
160 }
161 
setFrame(int frame1,int frame2,double blend)162 void MD3Model::setFrame(int frame1, int frame2, double blend)
163 {
164 	m_frame1 = frame1;
165 	m_frame2 = frame2;
166 	m_blend = blend;
167 }
168 
link(MD3Model * m)169 void MD3Model::link(MD3Model * m)
170 {
171 	m_links.push_back(m);
172 }
173 
draw()174 void MD3Model::draw()
175 {
176 	int f1 = m_frame1;
177 	int f2 = m_frame2;
178 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
179 	float pi = 3.1415;
180 	glEnable(GL_NORMALIZE);
181 	for(int j = 0; j < m_header.mesh_num; j++) {
182 		if(m_textures.find(m_meshes[j].tex) != m_textures.end()) {
183 			m_textures[m_meshes[j].tex].use();
184 		}
185 		glBegin(GL_TRIANGLES);
186 		for(int i = 0; i < m_meshes[j].triangles.size(); i++) {
187 			int v = m_meshes[j].header.vertex_num;
188 			md3Vertex_t v0 = blendVertex(m_meshes[j].vertices[v*f1+m_meshes[j].triangles[i].vertices[0]],
189 											m_meshes[j].vertices[v*f2+m_meshes[j].triangles[i].vertices[0]], m_blend);
190 			md3Vertex_t v1 = blendVertex(m_meshes[j].vertices[v*f1+m_meshes[j].triangles[i].vertices[1]],
191 											m_meshes[j].vertices[v*f2+m_meshes[j].triangles[i].vertices[1]], m_blend);
192 			md3Vertex_t v2 = blendVertex(m_meshes[j].vertices[v*f1+m_meshes[j].triangles[i].vertices[2]],
193 											m_meshes[j].vertices[v*f2+m_meshes[j].triangles[i].vertices[2]], m_blend);
194 			md3Normal_t n0 = m_meshes[j].normals[v*f1+m_meshes[j].triangles[i].vertices[0]];
195 			md3Normal_t n1 = m_meshes[j].normals[v*f1+m_meshes[j].triangles[i].vertices[1]];
196 			md3Normal_t n2 = m_meshes[j].normals[v*f1+m_meshes[j].triangles[i].vertices[2]];
197 			md3TexCoord_t tv0 = m_meshes[j].texcoords[m_meshes[j].triangles[i].vertices[0]];
198 			md3TexCoord_t tv1 = m_meshes[j].texcoords[m_meshes[j].triangles[i].vertices[1]];
199 			md3TexCoord_t tv2 = m_meshes[j].texcoords[m_meshes[j].triangles[i].vertices[2]];
200 			glNormal3f(n2.x, n2.y, n2.z);
201 			glTexCoord2f(tv2.coords[0], tv2.coords[1]);
202 			glVertex3f(v2.coords[0]*1.0/64, v2.coords[1]*1.0/64, v2.coords[2]*1.0/64);
203 			glNormal3f(n1.x, n1.y, n1.z);
204 			glTexCoord2f(tv1.coords[0], tv1.coords[1]);
205 			glVertex3f(v1.coords[0]*1.0/64, v1.coords[1]*1.0/64, v1.coords[2]*1.0/64);
206 			glNormal3f(n0.x, n0.y, n0.z);
207 			glTexCoord2f(tv0.coords[0], tv0.coords[1]);
208 			glVertex3f(v0.coords[0]*1.0/64, v0.coords[1]*1.0/64, v0.coords[2]*1.0/64);
209 		}
210 		glEnd();
211 	}
212 
213 	double b1 = (1 - m_blend);
214 	double b2 = m_blend;
215 	float mult[4][4] = { 0.0 };
216 	mult[3][3] = 1.0;
217 	for(int j = 0; j < m_header.tag_num; j++) {
218 		for(int l = 0; l < m_links.size(); l++) {
219 			if(string(m_links[l]->m_tagname) == string(m_frames[f1].tags[j].name)) {
220 				glPushMatrix();
221 				if(b2 < 0.1)
222 				glTranslatef(m_frames[f1].tags[j].origin[0],
223 								m_frames[f1].tags[j].origin[1],
224 								m_frames[f1].tags[j].origin[2]);
225 				else if(b2 > 0.9)
226 				glTranslatef(m_frames[f2].tags[j].origin[0],
227 								m_frames[f2].tags[j].origin[1],
228 								m_frames[f2].tags[j].origin[2]);
229 				else
230 				glTranslatef(b1*m_frames[f1].tags[j].origin[0]
231 								+ b2*m_frames[f2].tags[j].origin[0],
232 								b1*m_frames[f1].tags[j].origin[1]
233 								+ b2*m_frames[f2].tags[j].origin[1],
234 								b1*m_frames[f1].tags[j].origin[2]
235 								+ b2*m_frames[f2].tags[j].origin[2]);
236 				for(int r = 0; r < 3; r++) {
237 					for(int c = 0; c < 3; c++) {
238 						if(b2 < 0.1)
239 							mult[r][c] = m_frames[f1].tags[j].axis[r][c];
240 						else if(b2 > 0.9)
241 							mult[r][c] = m_frames[f2].tags[j].axis[r][c];
242 						else
243 						mult[r][c] = b1*m_frames[f1].tags[j].axis[r][c]
244 							+b2*m_frames[f2].tags[j].axis[r][c];
245 					}
246 				}
247 				glMultMatrixf((float*)mult);
248 				m_links[l]->draw();
249 				glPopMatrix();
250 			}
251 		}
252 	}
253 }
254 
printInfo() const255 void MD3Model::printInfo() const
256 {
257 	printHeader();
258 	printFrames();
259 	printMeshes();
260 	cout << "Found Tag: " << m_tagname << endl;
261 }
262 
printHeader() const263 void MD3Model::printHeader() const
264 {
265 	cout << "\nMD3 Header:" << endl;
266 	cout << "ID:\t\t\t" << m_header.ID << endl;
267 	cout << "Version:\t\t" << m_header.version << endl;
268 	cout << "Filename:\t\t" << m_header.name << endl;
269 	cout << "Number of Frames:\t" << m_header.frame_num << endl;
270 	cout << "Number of Tags:\t\t" << m_header.tag_num << endl;
271 	cout << "Number of Meshes:\t" << m_header.mesh_num << endl;
272 	cout << "Max Num Skins:\t\t" << m_header.max_skin_num << endl;
273 	cout << "Start Frame Position:\t" << m_header.frame_start << endl;
274 	cout << "Start Tag Position:\t" << m_header.tag_start << endl;
275 	cout << "Start Mesh Position:\t" << m_header.mesh_start << endl;
276 	cout << "Size of File:\t\t" << m_header.file_size << endl;
277 }
278 
printFrames() const279 void MD3Model::printFrames() const
280 {
281 	for (vector<md3Frame_t>::const_iterator fi = m_frames.begin(); fi != m_frames.end(); ++fi) {
282 		cout << "\nFrame:" << endl;
283 		cout << "Min Bound: (" << fi->header.min_bound[0] << "," << fi->header.min_bound[1] << "," << fi->header.min_bound[2] << ")" << endl;
284 		cout << "Max Bound: (" << fi->header.max_bound[0] << "," << fi->header.max_bound[1] << "," << fi->header.max_bound[2] << ")" << endl;
285 		cout << "Origin: (" << fi->header.origin[0] << "," << fi->header.origin[1] << "," << fi->header.origin[2] << ")" << endl;
286 		cout << "Bound Radius: " << fi->header.bound_radius << endl;
287 		cout << "Name: " << fi->header.name << endl;
288 		for (vector<md3Tag_t>::const_iterator ti = fi->tags.begin(); ti != fi->tags.end(); ++ti) {
289 			cout << "Tag name: " << ti->name << endl;
290 			cout << "Origin: (" << ti->origin[0] << "," << ti->origin[1] << "," << ti->origin[2] << ")" << endl;
291 			cout << "Axis: (" << ti->axis[0][0] << "," << ti->axis[0][1] << "," << ti->axis[0][2] << ")" << endl;
292 			cout << "Axis: (" << ti->axis[1][0] << "," << ti->axis[1][1] << "," << ti->axis[1][2] << ")" << endl;
293 			cout << "Axis: (" << ti->axis[2][0] << "," << ti->axis[2][1] << "," << ti->axis[2][2] << ")" << endl;
294 		}
295 	}
296 }
297 
printMeshes() const298 void MD3Model::printMeshes() const
299 {
300 	for (vector<md3Mesh_t>::const_iterator mi = m_meshes.begin(); mi != m_meshes.end(); ++mi) {
301 		cout << "\nMesh:" << endl;
302 		cout << "ID: " << mi->header.id << endl;
303 		cout << "Name: " << mi->header.name << endl;
304 		cout << "Number of Frames: " << mi->header.frame_num << endl;
305 		cout << "Number of Skins: " << mi->header.skin_num << endl;
306 		cout << "Number of Vertices: " << mi->header.vertex_num << endl;
307 		cout << "Number of Triangles: " << mi->header.triangle_num << endl;
308 		cout << "Triangles Start: " << mi->header.triangle_start << endl;
309 		cout << "Skins Start: " << mi->header.skin_start << endl;
310 		cout << "Texture Coords Start: " << mi->header.texcoord_start << endl;
311 		cout << "Vertices Start: " << mi->header.vertex_start << endl;
312 		cout << "Mesh Size: " << mi->header.mesh_size << endl;
313 		for (vector<md3Skin_t>::const_iterator si = mi->skins.begin(); si != mi->skins.end(); ++si) {
314 			cout << "Name: " << si->name << endl;
315 		}
316 	}
317 
318 }
319 
blendVertex(md3Vertex_t & v1,md3Vertex_t & v2,double b)320 MD3Model::md3Vertex_t MD3Model::blendVertex(md3Vertex_t & v1, md3Vertex_t & v2,
321 		double b)
322 {
323 	if(b < 0.1)
324 		return v1;
325 	else if(b > 0.9)
326 		return v2;
327 	double b1 = 1 - b;
328 	md3Vertex_t v;
329 	v.coords[0] = (signed short)(b1*v1.coords[0] + b*v2.coords[0]);
330 	v.coords[1] = (signed short)(b1*v1.coords[1] + b*v2.coords[1]);
331 	v.coords[2] = (signed short)(b1*v1.coords[2] + b*v2.coords[2]);
332 	return v;
333 }
334 
335 // End of file md3model.cpp
336 
337