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/Model.h>
22 #include <3dsparse/ModelMaths.h>
23 #include <common/Defines.h>
24 
Model()25 Model::Model() :
26 	startFrame_(0), totalFrames_(0),
27 	noTriangles_(0),
28 	texturesUsed_(false)
29 {
30 }
31 
~Model()32 Model::~Model()
33 {
34 	while (!meshes_.empty())
35 	{
36 		Mesh *mesh = meshes_.back();
37 		meshes_.pop_back();
38 		delete mesh;
39 	}
40 	while (!bones_.empty())
41 	{
42 		Bone *bone = bones_.back();
43 		bones_.pop_back();
44 		delete bone;
45 	}
46 	while (!baseBoneTypes_.empty())
47 	{
48 		BoneType *boneType = baseBoneTypes_.back();
49 		baseBoneTypes_.pop_back();
50 		delete boneType;
51 	}
52 }
53 
centre()54 void Model::centre()
55 {
56 	max_ = meshes_.front()->getMax();
57 	min_ = meshes_.front()->getMin();
58 	DIALOG_ASSERT(!meshes_.empty());
59 
60 	std::vector<Mesh *>::iterator itor;
61 	for (itor = meshes_.begin();
62 		itor != meshes_.end();
63 		++itor)
64 	{
65 		max_[0] = MAX(max_[0], (*itor)->getMax()[0]);
66 		max_[1] = MAX(max_[1], (*itor)->getMax()[1]);
67 		max_[2] = MAX(max_[2], (*itor)->getMax()[2]);
68 
69 		min_[0] = MIN(min_[0], (*itor)->getMin()[0]);
70 		min_[1] = MIN(min_[1], (*itor)->getMin()[1]);
71 		min_[2] = MIN(min_[2], (*itor)->getMin()[2]);
72 	}
73 
74 	FixedVector centre = (max_ + min_) / -2;
75 	for (itor = meshes_.begin();
76 		itor != meshes_.end();
77 		++itor)
78 	{
79 		(*itor)->move(centre);
80 	}
81 	min_ += centre;
82 	max_ += centre;
83 }
84 
setup()85 void Model::setup()
86 {
87 	centre();
88 	setupBones();
89 	setupColor();
90 	countTextures();
91 }
92 
countTextures()93 void Model::countTextures()
94 {
95 	unsigned int texturesUsed = 0;
96 	std::vector<Mesh *>::iterator itor;
97 	for (itor = meshes_.begin();
98 		itor != meshes_.end();
99 		++itor)
100 	{
101 		Mesh *mesh = *itor;
102 		if (mesh->getTextureName()[0])
103 		{
104 			texturesUsed++;
105 		}
106 		noTriangles_ += (int) mesh->getFaces().size();
107 	}
108 	//DIALOG_ASSERT(texturesUsed == meshes_.size());
109 	texturesUsed_ = (texturesUsed > 0);
110 }
111 
setupColor()112 void Model::setupColor()
113 {
114 	FixedVector lightpos(fixed(true, -3000), fixed(true, -2000), 1);
115 	lightpos.StoreNormalize();
116 
117 	std::vector<Mesh *>::iterator itor;
118 	for (itor = meshes_.begin();
119 		itor != meshes_.end();
120 		++itor)
121 	{
122 		Mesh *mesh = (*itor);
123 
124 		std::vector<Face *>::iterator itor;
125 		for (itor = mesh->getFaces().begin();
126 			itor != mesh->getFaces().end();
127 			++itor)
128 		{
129 			Face *face = *itor;
130 			for (int i=0; i<3; i++)
131 			{
132 				Vertex *vertex = mesh->getVertex(face->v[i]);
133 				FixedVector &normal = face->normal[i];
134 
135 				const fixed ambientLight = fixed(true, 2000);
136 				const fixed diffuseLight = fixed(true, 8000);
137 				fixed diffuseLightMult =
138 					(((lightpos.dotP(normal.Normalize())) / 2) + fixed(true, 5000));
139 				fixed intense = diffuseLightMult * diffuseLight + ambientLight;
140 				if (intense > 1) intense = 1;
141 				vertex->lightintense[0] = intense;
142 				vertex->lightintense[1] = intense;
143 				vertex->lightintense[2] = intense;
144 			}
145 		}
146 	}
147 }
148 
setupBones()149 void Model::setupBones()
150 {
151 	for (unsigned int b=0; b<bones_.size(); b++)
152 	{
153 		baseBoneTypes_.push_back(new BoneType());
154 	}
155 
156 	for (unsigned int b=0; b<bones_.size(); b++)
157 	{
158 		Bone *bone = bones_[b];
159 		BoneType *type = baseBoneTypes_[b];
160 
161 		// Find the parent bone
162 		for (unsigned int p=0; p<bones_.size(); p++)
163 		{
164 			Bone *parent = bones_[p];
165 			if (0 == strcmp(bone->getParentName(), parent->getName()))
166 			{
167 				type->parent_ = p;
168 				break;
169 			}
170 		}
171 
172 		// Set rotation and position
173 		FixedVector rot;
174 		rot[0] = bone->getRotation()[0] * 180 / fixed::XPI;
175 		rot[1] = bone->getRotation()[1] * 180 / fixed::XPI;
176 		rot[2] = bone->getRotation()[2] * 180 / fixed::XPI;
177 
178 		ModelMaths::angleMatrix(rot, type->relative_);
179 		type->relative_[0][3] = bone->getPosition()[0];
180 		type->relative_[1][3] = bone->getPosition()[1];
181 		type->relative_[2][3] = bone->getPosition()[2];
182 
183 		// Setup child relations
184 		if (type->parent_ != -1)
185 		{
186 			BoneType *parent = baseBoneTypes_[type->parent_];
187 
188 			ModelMaths::concatTransforms(parent->absolute_, type->relative_, type->absolute_);
189 			memcpy(type->final_, type->absolute_, sizeof(BoneMatrixType));
190 		}
191 		else // No parent
192 		{
193 			memcpy(type->absolute_, type->relative_, sizeof(BoneMatrixType));
194 			memcpy(type->final_, type->relative_, sizeof(BoneMatrixType));
195 		}
196 	}
197 
198 	// Move vertexes to align with the bones
199 	bool referenceBones = false;
200 	for (unsigned int i=0; i<meshes_.size(); i++)
201 	{
202 		Mesh *mesh = meshes_[i];
203 		for (unsigned int j=0; j<mesh->getVertexes().size(); j++)
204 		{
205 			Vertex *vertex = mesh->getVertex(j);
206 			if (vertex->boneIndex != -1)
207 			{
208 				DIALOG_ASSERT(vertex->boneIndex < int(bones_.size()));
209 
210 				BoneType *type = baseBoneTypes_[vertex->boneIndex];
211 				referenceBones = true;
212 
213 				// Note: Translation of MS to S3D coords
214 
215 				// Translation
216 				vertex->position[0] -= type->absolute_[0][3];
217 				vertex->position[1] -= type->absolute_[2][3];
218 				vertex->position[2] -= type->absolute_[1][3];
219 
220 				// Rotation
221 				FixedVector tmpPos;
222 				tmpPos[0] = vertex->position[0];
223 				tmpPos[1] = vertex->position[2];
224 				tmpPos[2] = vertex->position[1];
225 
226 				FixedVector tmp;
227 				ModelMaths::vectorIRotate(tmpPos, type->absolute_, tmp);
228 				vertex->position[0] = tmp[0];
229 				vertex->position[1] = tmp[2];
230 				vertex->position[2] = tmp[1];
231 			}
232 		}
233 	}
234 
235 	if (!referenceBones) totalFrames_ = 1;
236 }
237