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