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