1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <3dsparse/MSModelFactory.h>
22 #include <common/Defines.h>
23
MSModelFactory()24 MSModelFactory::MSModelFactory() : lineNo_(0)
25 {
26 }
27
~MSModelFactory()28 MSModelFactory::~MSModelFactory()
29 {
30 }
31
createModel(const char * fileName)32 Model *MSModelFactory::createModel(const char *fileName)
33 {
34 Model *model = new Model();
35
36 FILE *in = fopen(fileName, "r");
37 if (!in)
38 {
39 S3D::dialogExit("MSModelFactory", S3D::formatStringBuffer(
40 "Failed to open MS model \"%s\"",
41 fileName));
42 }
43 loadFile(in, fileName, model);
44 model->setup();
45 fclose(in);
46
47 return model;
48 }
49
getNextLine(char * line,FILE * in)50 bool MSModelFactory::getNextLine(char *line, FILE *in)
51 {
52 char * wincr;
53 while (fgets(line, 256, in) != 0)
54 {
55 lineNo_++;
56 if ((wincr=strchr(line,'\r')))
57 {
58 *wincr='\n';
59 *(wincr + 1) = '\0';
60 }
61
62 if ((line[0] == '\\' && line[1] == '\\') ||
63 (line[0] == '/' && line[1] == '/') ||
64 (line[0] == '\0') ||
65 (line[0] == '\n'))
66 {
67 // Skip this line
68 }
69 else return true;
70 }
71
72 return false;
73 }
74
returnError(const char * fileName,const std::string & error)75 void MSModelFactory::returnError(const char *fileName, const std::string &error)
76 {
77 S3D::dialogExit("MSModelFactory", S3D::formatStringBuffer("%s in file %i:%s",
78 error.c_str(), lineNo_, fileName));
79 }
80
loadFile(FILE * in,const char * fileName,Model * model)81 void MSModelFactory::loadFile(FILE *in, const char *fileName, Model *model)
82 {
83 char filePath[256];
84 snprintf(filePath, sizeof(filePath), "%s", fileName);
85 char fixed1[20], fixed2[20], fixed3[20];
86 char fixed4[20], fixed5[20], fixed6[20];
87
88 char *sep;
89 while ((sep=strchr(filePath, '\\'))) *sep = '/';
90 sep = strrchr(filePath, '/');
91 if (sep) *sep = '\0';
92
93 char buffer[256];
94 int frames = 0;
95 if (!getNextLine(buffer, in)) returnError(fileName, "No frames");
96 if (sscanf(buffer, "Frames: %i", &frames) != 1)
97 returnError(fileName, "Incorrect frames format");
98 model->setTotalFrames(frames);
99
100 if (!getNextLine(buffer, in)) returnError(fileName, "No frame");
101 if (sscanf(buffer, "Frame: %i", &frames) != 1)
102 returnError(fileName, "Incorrect frame format");
103 model->setStartFrame(frames);
104
105 // Read number meshes
106 int noMeshes = 0;
107 if (!getNextLine(buffer, in)) returnError(fileName, "No meshes");
108 if (sscanf(buffer, "Meshes: %i", &noMeshes) != 1)
109 returnError(fileName, "Incorrect meshes format");
110
111 std::vector<int> meshMaterials;
112 for (int i=0; i<noMeshes; i++)
113 {
114 // Read the mesh name, flags and material indices
115 char meshName[256];
116 int meshFlags, meshMatIndex;
117 if (!getNextLine(buffer, in))
118 returnError(fileName, "No mesh name");
119 if (sscanf(buffer, "%s %i %i", meshName, &meshFlags, &meshMatIndex) != 3)
120 returnError(fileName, "Incorrect mesh name format");
121 meshMaterials.push_back(meshMatIndex);
122
123 // Create and add the new model
124 Mesh *mesh = new Mesh(meshName);
125 model->addMesh(mesh);
126
127 // Read no vertices
128 int noVertices = 0;
129 if (!getNextLine(buffer, in))
130 returnError(fileName, "No num vertices");
131 if (sscanf(buffer, "%i", &noVertices) != 1)
132 returnError(fileName, "Incorrect num vertices format");
133
134 int j;
135 std::vector<FixedVector> tcoords;
136 for (j=0; j<noVertices; j++)
137 {
138 // Read the current vertex
139 int vertexFlags;
140 FixedVector texCoord;
141 Vertex vertex;
142 if (!getNextLine(buffer, in))
143 returnError(fileName, "No vertices");
144 if (sscanf(buffer, "%i %s %s %s %s %s %i",
145 &vertexFlags,
146 fixed1, fixed2, fixed3,
147 fixed4, fixed5, &vertex.boneIndex) != 7)
148 returnError(fileName, "Incorrect vertices format");
149
150 vertex.position[0] = fixed(fixed1);
151 vertex.position[2] = fixed(fixed2);
152 vertex.position[1] = fixed(fixed3);
153 texCoord[0] = fixed(fixed4);
154 texCoord[1] = fixed(1)-fixed(fixed5);
155
156 tcoords.push_back(texCoord);
157 mesh->insertVertex(vertex);
158 }
159
160 // Read no normals
161 std::vector<FixedVector> normals;
162 int noNormals = 0;
163 if (!getNextLine(buffer, in))
164 returnError(fileName, "No num normals");
165 if (sscanf(buffer, "%i", &noNormals) != 1)
166 returnError(fileName, "Incorrect num normals format");
167 for (j=0; j<noNormals; j++)
168 {
169 // Read the current normal
170 FixedVector normal;
171 if (!getNextLine(buffer, in))
172 returnError(fileName, "No normal");
173 if (sscanf(buffer, "%s %s %s",
174 fixed1, fixed2, fixed3) != 3)
175 returnError(fileName, "Incorrect normal format");
176
177 normal[0] = fixed(fixed1);
178 normal[2] = fixed(fixed2);
179 normal[1] = fixed(fixed3);
180
181 normals.push_back(normal.Normalize());
182 }
183
184 // Read no faces
185 int noFaces = 0;
186 if (!getNextLine(buffer, in))
187 returnError(fileName, "No num faces");
188 if (sscanf(buffer, "%i", &noFaces) != 1)
189 returnError(fileName, "Incorrect num faces format");
190 for (j=0; j<noFaces; j++)
191 {
192 // Read the current face
193 int faceFlags, sGroup;
194 int nIndex1, nIndex2, nIndex3;
195 Face face;
196 if (!getNextLine(buffer, in))
197 returnError(fileName, "No face");
198 if (sscanf(buffer, "%i %i %i %i %i %i %i %i",
199 &faceFlags,
200 &face.v[0], &face.v[2], &face.v[1],
201 &nIndex1, &nIndex3, &nIndex2,
202 &sGroup) != 8)
203 returnError(fileName, "Incorrect face format");
204
205 mesh->insertFace(face);
206 DIALOG_ASSERT (nIndex1 < (int) normals.size());
207 mesh->setFaceNormal(normals[nIndex1], j, 0);
208 DIALOG_ASSERT (nIndex2 < (int) normals.size());
209 mesh->setFaceNormal(normals[nIndex2], j, 1);
210 DIALOG_ASSERT (nIndex3 < (int) normals.size());
211 mesh->setFaceNormal(normals[nIndex3], j, 2);
212
213 DIALOG_ASSERT (face.v[0] < (int) tcoords.size());
214 mesh->setFaceTCoord(tcoords[face.v[0]], j, 0);
215 DIALOG_ASSERT (face.v[1] < (int) tcoords.size());
216 mesh->setFaceTCoord(tcoords[face.v[1]], j, 1);
217 DIALOG_ASSERT (face.v[2] < (int) tcoords.size());
218 mesh->setFaceTCoord(tcoords[face.v[2]], j, 2);
219 }
220 }
221
222 // Read number materials
223 int noMaterials = 0;
224 if (!getNextLine(buffer, in))
225 returnError(fileName, "No num materials");
226 if (sscanf(buffer, "Materials: %i", &noMaterials) != 1)
227 returnError(fileName, "Incorrect num materials format");
228
229 for (int m=0; m<noMaterials; m++)
230 {
231 // material: name
232 char materialName[256];
233 if (!getNextLine(buffer, in))
234 returnError(fileName, "No material name");
235 if (sscanf(buffer, "%s", materialName) != 1)
236 returnError(fileName, "Incorrect material name format");
237
238 // ambient
239 FixedVector4 ambient;
240 if (!getNextLine(buffer, in))
241 returnError(fileName, "No material ambient");
242 if (sscanf(buffer, "%s %s %s %s",
243 fixed1, fixed2, fixed3, fixed4) != 4)
244 returnError(fileName, "Incorrect material ambient format");
245 ambient[0] = fixed(fixed1);
246 ambient[1] = fixed(fixed2);
247 ambient[2] = fixed(fixed3);
248 ambient[3] = fixed(fixed4);
249
250 // diffuse
251 FixedVector4 diffuse;
252 if (!getNextLine(buffer, in))
253 returnError(fileName, "No material diffuse");
254 if (sscanf(buffer, "%s %s %s %s",
255 fixed1, fixed2, fixed3, fixed4) != 4)
256 returnError(fileName, "Incorrect material diffuse format");
257 diffuse[0] = fixed(fixed1);
258 diffuse[1] = fixed(fixed2);
259 diffuse[2] = fixed(fixed3);
260 diffuse[3] = fixed(fixed4);
261
262 // specular
263 FixedVector4 specular;
264 if (!getNextLine(buffer, in))
265 returnError(fileName, "No material specular");
266 if (sscanf(buffer, "%s %s %s %s",
267 fixed1, fixed2, fixed3, fixed4) != 4)
268 returnError(fileName, "Incorrect material specular format");
269 specular[0] = fixed(fixed1);
270 specular[1] = fixed(fixed2);
271 specular[2] = fixed(fixed3);
272 specular[3] = fixed(fixed4);
273
274 // emissive
275 FixedVector4 emissive;
276 if (!getNextLine(buffer, in))
277 returnError(fileName, "No material emissive");
278 if (sscanf(buffer, "%s %s %s %s",
279 fixed1, fixed2, fixed3, fixed4) != 4)
280 returnError(fileName, "Incorrect material emissive format");
281 emissive[0] = fixed(fixed1);
282 emissive[1] = fixed(fixed2);
283 emissive[2] = fixed(fixed3);
284 emissive[3] = fixed(fixed4);
285
286 // shininess
287 fixed shininess;
288 if (!getNextLine(buffer, in))
289 returnError(fileName, "No material shininess");
290 if (sscanf(buffer, "%s", fixed1) != 1)
291 returnError(fileName, "Incorrect material shininess format");
292 shininess = fixed(fixed1);
293
294 // transparency
295 fixed transparency;
296 if (!getNextLine(buffer, in))
297 returnError(fileName, "No material transparency");
298 if (sscanf(buffer, "%s", &fixed1) != 1)
299 returnError(fileName, "Incorrect material transparency format");
300 transparency = fixed(fixed1);
301
302 // color map
303 char textureName[256];
304 char fullTextureName[256];
305 if (!getNextLine(buffer, in))
306 returnError(fileName, "No material texture");
307 if (sscanf(buffer, "%s", textureName) != 1)
308 returnError(fileName, "No material texture format");
309 textureName[strlen(textureName)-1] = '\0';
310 snprintf(fullTextureName, 256, "%s/%s", filePath, &textureName[1]);
311 while (sep=strchr(fullTextureName, '\\')) *sep = '/';
312
313 // alphamap
314 char textureNameAlpha[256];
315 char fullTextureAlphaName[256];
316 if (!getNextLine(buffer, in))
317 returnError(fileName, "No material alpha texture");
318 if (sscanf(buffer, "%s", textureNameAlpha) != 1)
319 returnError(fileName, "No material alpha texture format");
320 textureNameAlpha[strlen(textureNameAlpha)-1] = '\0';
321 snprintf(fullTextureAlphaName, 256, "%s/%s", filePath, &textureNameAlpha[1]);
322 while (sep=strchr(fullTextureAlphaName, '\\')) *sep = '/';
323
324 // Assign this material to the appropriate meshes
325 int modelIndex = 0;
326 std::vector<Mesh *>::iterator mitor;
327 for (mitor = model->getMeshes().begin();
328 mitor != model->getMeshes().end();
329 ++mitor, modelIndex++)
330 {
331 if (meshMaterials[modelIndex] == m)
332 {
333 Mesh *mesh = *mitor;
334 if (textureName[1]) // as the string starts with a "
335 {
336 mesh->setTextureName(fullTextureName);
337 if (!S3D::fileExists(fullTextureName))
338 {
339 returnError(fileName,
340 S3D::formatStringBuffer("Failed to find texture \"%s\"",
341 fullTextureName));
342 }
343 }
344 if (textureNameAlpha[1])
345 {
346 mesh->setATextureName(fullTextureAlphaName);
347 if (!S3D::fileExists(fullTextureAlphaName))
348 {
349 returnError(fileName,
350 S3D::formatStringBuffer("Failed to find alpha texture \"%s\"",
351 fullTextureAlphaName));
352 }
353 }
354 mesh->getDiffuseColor() = diffuse;
355 mesh->getAmbientColor() = ambient;
356 mesh->getSpecularColor() = specular;
357 mesh->getEmissiveColor() = emissive;
358 mesh->getShininessColor() = shininess;
359 mesh->getDiffuseNoTexColor() = diffuse;
360 mesh->getAmbientNoTexColor() = ambient;
361 mesh->getSpecularNoTexColor() = specular;
362 mesh->getEmissiveNoTexColor() = emissive;
363 }
364 }
365 }
366
367 // Setup meshes with no materials
368 int modelIndex = 0;
369 std::vector<Mesh *>::iterator mitor;
370 for (mitor = model->getMeshes().begin();
371 mitor != model->getMeshes().end();
372 ++mitor, modelIndex++)
373 {
374 int materialIndex = meshMaterials[modelIndex];
375 if (materialIndex == -1)
376 {
377 Mesh *mesh = *mitor;
378
379 FixedVector4 ambientColor(fixed(true, 3000), fixed(true, 3000), fixed(true, 3000), 1);
380 FixedVector4 diffuseColor(fixed(true, 8000), fixed(true, 8000), fixed(true, 8000), 1);
381 mesh->getAmbientColor() = ambientColor;
382 mesh->getDiffuseColor() = diffuseColor;
383 mesh->getEmissiveColor() = FixedVector4::getNullVector();
384 mesh->getSpecularColor() = FixedVector4::getNullVector();
385
386 mesh->getAmbientNoTexColor() = ambientColor;
387 mesh->getDiffuseNoTexColor() = diffuseColor;
388 mesh->getEmissiveNoTexColor() = FixedVector4::getNullVector();
389 mesh->getSpecularNoTexColor() = FixedVector4::getNullVector();
390
391 mesh->getShininessColor() = 0;
392 }
393 }
394
395
396 ////////////////
397 // The bone's position and rotation are left in the milkshape native xyz coord
398 // system and are not read in translated into the S3D system.
399 // The translation is done during the bone calculation at runtime
400 ///////////////
401
402 // Read number bones
403 int noBones = 0;
404 if (!getNextLine(buffer, in))
405 returnError(fileName, "No num bones");
406 if (sscanf(buffer, "Bones: %i", &noBones) != 1)
407 returnError(fileName, "Incorrect num bones format");
408
409 for (int b=0; b<noBones; b++)
410 {
411 // bone: name
412 char boneName[256];
413 if (!getNextLine(buffer, in))
414 returnError(fileName, "No bone name");
415 if (sscanf(buffer, "%s", boneName) != 1)
416 returnError(fileName, "Incorrect bone name format");
417
418 // bone parent
419 char boneParentName[256];
420 if (!getNextLine(buffer, in))
421 returnError(fileName, "No bone parent name");
422 if (sscanf(buffer, "%s", boneParentName) != 1)
423 returnError(fileName, "Incorrect bone parent name format");
424
425 // flags, position, rotation
426 int boneFlags;
427 FixedVector bonePos, boneRot;
428 if (!getNextLine(buffer, in))
429 returnError(fileName, "No bone pos/rot");
430 if (sscanf(buffer, "%i %s %s %s %s %s %s",
431 &boneFlags,
432 fixed1, fixed2, fixed3,
433 fixed4, fixed5, fixed6) != 7)
434 returnError(fileName, "Incorrect bone pos/rot format");
435 bonePos[0] = fixed(fixed1);
436 bonePos[1] = fixed(fixed2);
437 bonePos[2] = fixed(fixed3);
438 boneRot[0] = fixed(fixed4);
439 boneRot[1] = fixed(fixed5);
440 boneRot[2] = fixed(fixed6);
441
442 Bone *bone = new Bone(boneName);
443 bone->setParentName(boneParentName);
444 bone->setPosition(bonePos);
445 bone->setRotation(boneRot);
446
447 // position key
448 int noPositionKeys = 0;
449 if (!getNextLine(buffer, in))
450 returnError(fileName, "No bone position keys");
451 if (sscanf(buffer, "%i", &noPositionKeys) != 1)
452 returnError(fileName, "Incorrect bone position keys format");
453
454 for (int p=0; p<noPositionKeys; p++)
455 {
456 fixed time;
457 FixedVector position;
458 if (!getNextLine(buffer, in))
459 returnError(fileName, "No bone position key");
460 if (sscanf(buffer, "%s %s %s %s",
461 fixed1,
462 fixed2, fixed3, fixed4) != 4)
463 returnError(fileName, "Incorrect bone position key");
464
465 time = fixed(fixed1);
466 position[0] = fixed(fixed2);
467 position[1] = fixed(fixed3);
468 position[2] = fixed(fixed4);
469
470 BonePositionKey *key = new BonePositionKey(time, position);
471 bone->addPositionKey(key);
472 }
473
474 // rotation key
475 int noRotationKeys = 0;
476 if (!getNextLine(buffer, in))
477 returnError(fileName, "No bone rotation keys");
478 if (sscanf(buffer, "%i", &noRotationKeys) != 1)
479 returnError(fileName, "Incorrect bone rotation keys format");
480
481 for (int r=0; r<noRotationKeys; r++)
482 {
483 fixed time;
484 FixedVector rotation;
485 if (!getNextLine(buffer, in))
486 returnError(fileName, "No bone position key");
487 if (sscanf(buffer, "%s %s %s %s",
488 fixed1,
489 fixed2, fixed3, fixed4) != 4)
490 returnError(fileName, "Incorrect bone position key");
491 time = fixed(fixed1);
492 rotation[0] = fixed(fixed2);
493 rotation[1] = fixed(fixed3);
494 rotation[2] = fixed(fixed4);
495
496 BoneRotationKey *key = new BoneRotationKey(time, rotation);
497 bone->addRotationKey(key);
498 }
499
500 // Add bone
501 model->addBone(bone);
502 }
503 }
504