Add "Apply transformations" feature (no connectors or frames done yet)
[wmit:wmit.git] / src / formats / Mesh.cpp
1 /*
2         Copyright 2010 Warzone 2100 Project
3
4         This file is part of WMIT.
5
6         WMIT 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 3 of the License, or
9         (at your option) any later version.
10
11         WMIT 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
17         along with WMIT.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "Mesh.hpp"
21
22 #include <algorithm>
23 #include <iterator>
24 #include <map>
25 #include <set>
26
27 #include <cmath>
28
29 #include <sstream>
30
31 #ifdef LIB3DS_VERSION_1
32 #include <lib3ds/mesh.h>
33 #include <lib3ds/vector.h>
34 #include <lib3ds/matrix.h>
35 #include <lib3ds/material.h>
36 #else
37 #include <lib3ds.h>
38 #endif
39
40 #include "Generic.hpp"
41 #include "Util.hpp"
42 #include "Pie.hpp"
43 #include "Vector.hpp"
44
45 Mesh::Mesh()
46 {
47         defaultConstructor();
48 }
49
50 Mesh::Mesh(const Pie3Level& p3, float uvEps, float vertEps)
51 {
52         std::vector<Pie3Polygon>::const_iterator itL;
53
54         WZMVertex::less_wEps compare(vertEps);
55         std::multimap<WZMVertex, unsigned, WZMVertex::less_wEps> tmpMMap(compare);
56
57         std::multimap<WZMVertex, unsigned>::iterator itMM;
58         std::pair<std::multimap<WZMVertex, unsigned>::iterator,
59                                 std::multimap<WZMVertex, unsigned>::iterator> ret;
60
61         unsigned vIdx;
62         unsigned vert;
63         unsigned frame;
64         bool foundMatch;
65
66         defaultConstructor();
67
68         /*
69          *      Try to prevent duplicate vertices
70          *      (remember, different UV's, or animations,
71          *       will cause unavoidable duplication)
72          *      so that our transformed vertex cache isn't
73          *      completely useless.
74          */
75
76         if (m_textureArrays.size() == 0)
77         {
78                 m_textureArrays.push_back(TexArray());
79         }
80
81         // For each pie3 polygon
82         for (itL = p3.m_polygons.begin(); itL != p3.m_polygons.end(); ++itL)
83         {
84                 IndexedTri iTri;
85
86                 // For all 3 vertices of the triangle
87                 for (vert = 0; vert < 3; ++vert)
88                 {
89                         WZMVertex wzmVert = p3.m_points[itL->getIndex(vert)];
90                         ret = tmpMMap.equal_range(wzmVert);
91                         foundMatch = false;
92
93                         // Only check if match is possible
94                         if (itL->m_frames <= m_textureArrays.size())
95                         {
96                                 // For each potential match
97                                 for (itMM = ret.first; itMM != ret.second; ++itMM)
98                                 {
99                                         vIdx = itMM->second;
100
101                                         // Compare each animation frame
102                                         for (frame = 0; frame < itL->m_frames; ++frame)
103                                         {
104                                                 // Approximate comparison, helps kill duplicates
105                                                 const WZMUV::equal_wEps compare(uvEps);
106                                                 if (!compare(m_textureArrays[frame][vIdx], itL->getUV(vert, frame)))
107                                                 {
108                                                         break; // Not equal
109                                                 }
110                                         }
111
112                                         // if all frames were equal
113                                         if (!(frame < itL->m_frames))
114                                         {
115                                                 foundMatch = true;
116                                                 break; // Stop looking
117                                         }
118                                 }
119                         }
120
121                         if (!foundMatch)
122                         {
123                                 unsigned frames2Do = std::max<size_t>(itL->m_frames, m_textureArrays.size());
124                                 vIdx = m_vertexArray.size();
125                                 // add the vertex to both the multimap and the vertex array
126                                 m_vertexArray.push_back(wzmVert);
127                                 tmpMMap.insert(std::make_pair(wzmVert, vIdx));
128
129                                 m_textureArrays.reserve(frames2Do);
130
131                                 // add the uv's to the texture arrays
132                                 for (frame = 0; frame < frames2Do; ++frame)
133                                 {
134                                         if (m_textureArrays.size() < frame + 1)
135                                         {
136                                                 // Expand the texture array arrays
137                                                 m_textureArrays.push_back(m_textureArrays.back());
138                                                 m_textureArrays[frame][vIdx] = itL->getUV(vert, frame % itL->m_frames);
139                                         }
140                                         else
141                                         {
142                                                 m_textureArrays[frame].push_back(itL->getUV(vert, frame % itL->m_frames));
143                                         }
144                                 }
145                         }
146
147                         // Set the index
148                         iTri[vert] = vIdx;
149                 }
150
151                 m_indexArray.push_back(iTri);
152         }
153 }
154
155 Mesh::Mesh(const Lib3dsMesh& mesh3ds)
156 {
157         const bool swapYZ = true;
158         const bool reverseWinding = true;
159         const bool invertV = true;
160         const bool transform = true;
161
162         const WZMVertex::less_wEps vertLess; // For make_mypair
163         const WZMUV::less_wEps uvLess;
164
165         typedef std::set<mypair<WZMVertex, WZMUV,
166                 WZMVertex::less_wEps, WZMUV::less_wEps> > t_pairSet;
167
168         t_pairSet pairSet;
169
170         std::pair<t_pairSet::iterator, bool> inResult;
171
172         std::vector<unsigned> mapping;
173         std::vector<unsigned>::iterator itMap;
174
175         unsigned i, j;
176
177         IndexedTri idx; // temporaries
178         WZMVertex tmpVert;
179         WZMUV tmpUV;
180
181         m_textureArrays.push_back(TexArray()); // only one supported from 3DS
182 #ifdef LIB3DS_VERSION_1
183         m_vertexArray.reserve(mesh3ds.points);
184         m_textureArrays[0].reserve(mesh3ds.points);
185         m_indexArray.reserve(mesh3ds.faces);
186 #else
187         m_vertexArray.reserve(mesh3ds.nvertices);
188         m_textureArrays[0].reserve(mesh3ds.nvertices);
189         m_indexArray.reserve(mesh3ds.nfaces);
190 #endif
191
192         if (isValidWzName(mesh3ds.name))
193         {
194                 m_name = mesh3ds.name;
195         }
196
197 #ifdef LIB3DS_VERSION_1
198         for (i = 0; i < mesh3ds.faces; ++i)
199         {
200                 Lib3dsFace* face = &mesh3ds.faceL[i];
201 #else
202         for (i = 0; i < mesh3ds.nfaces; ++i)
203         {
204                 Lib3dsFace* face = &mesh3ds.faces[i];
205 #endif
206
207                 for (j = 0; j < 3; ++j)
208                 {
209 #ifdef LIB3DS_VERSION_1
210                         Lib3dsVector pos;
211
212                         if (transform)
213                         {
214                                 lib3ds_vector_transform(pos,
215                                                                                 const_cast<Lib3dsMatrix&>(mesh3ds.matrix),
216                                                                                 mesh3ds.pointL[face->points[j]].pos);
217                         }
218                         else
219                         {
220                                 lib3ds_vector_copy(pos,
221                                                                    mesh3ds.pointL[face->points[j]].pos);
222                         }
223 #else
224                         float pos[3];
225
226                         if (transform)
227                         {
228                                 lib3ds_vector_transform(pos,
229                                                                                 const_cast<float (*)[4]>(mesh3ds.matrix),
230                                                                                 mesh3ds.vertices[face->index[j]]);
231                         }
232                         else
233                         {
234                                 lib3ds_vector_copy(pos,
235                                                                    mesh3ds.vertices[face->index[j]]);
236                         }
237 #endif
238
239                         if (swapYZ)
240                         {
241                                 tmpVert.x() = pos[0];
242                                 tmpVert.y() = pos[2];
243                                 tmpVert.z() = pos[1];
244                         }
245                         else
246                         {
247                                 tmpVert.x() = pos[0];
248                                 tmpVert.y() = pos[1];
249                                 tmpVert.z() = pos[2];
250                         }
251
252 #ifdef LIB3DS_VERSION_1
253                         if (mesh3ds.points == mesh3ds.texels)
254                         {
255                                 tmpUV.u() = mesh3ds.texelL[face->points[j]][0];
256                                 if (invertV)
257                                 {
258                                         tmpUV.v() = 1.0f - mesh3ds.texelL[face->points[j]][1];
259                                 }
260                                 else
261                                 {
262                                         tmpUV.v() = mesh3ds.texelL[face->points[j]][1];
263                                 }
264                         }
265                         else
266                         {
267                                 tmpUV = WZMUV();
268                         }
269 #else
270                         tmpUV.u() = mesh3ds.texcos[face->index[j]][0];
271                         if (invertV)
272                         {
273                                 tmpUV.v() = 1.0f - mesh3ds.texcos[face->index[j]][1];
274                         }
275                         else
276                         {
277                                 tmpUV.v() = mesh3ds.texcos[face->index[j]][1];
278                         }
279 #endif
280
281                         inResult = pairSet.insert(make_mypair(tmpVert,
282                                                                                                   tmpUV,
283                                                                                                   vertLess,
284                                                                                                   uvLess));
285
286                         if (!inResult.second)
287                         {
288                                 idx[j] = mapping[std::distance(pairSet.begin(), inResult.first)];
289                         }
290                         else
291                         {
292                                 itMap = mapping.begin();
293                                 std::advance(itMap, std::distance(pairSet.begin(), inResult.first));
294                                 mapping.insert(itMap, m_vertexArray.size());
295                                 idx[j] = m_vertexArray.size();
296                                 m_vertexArray.push_back(tmpVert);
297                                 m_textureArrays[0].push_back(tmpUV);
298                         }
299                 }
300
301                 if (reverseWinding)
302                 {
303                         std::swap(idx.b(), idx.c());
304                 }
305
306                 m_indexArray.push_back(idx);
307         }
308
309         // TODO: Check if 3DS animation data can be used with our Frames
310 }
311
312 Mesh::~Mesh()
313 {
314 }
315
316 Pie3Level Mesh::backConvert(const Mesh& wzmMesh)
317 {
318         return wzmMesh;
319 }
320
321 Mesh::operator Pie3Level() const
322 {
323         Pie3Level p3;
324
325         std::vector<Pie3Vertex>::iterator itPV;
326
327         std::vector<IndexedTri>::const_iterator itTri;
328
329         unsigned i;
330
331         /* Note:
332          * WZM will have duplicates due to uv map differences
333          * so we remove those when converting
334          */
335
336         for (itTri = m_indexArray.begin(); itTri != m_indexArray.end(); ++itTri)
337         {
338                 Pie3Polygon p3Poly;
339                 Pie3UV  p3UV;
340
341                 p3Poly.m_flags = 0x200;
342
343                 for (i = 0; i < 3; ++i)
344                 {
345                         typedef Pie3Vertex::equal_wEps equals;
346                         mybinder1st<equals> compare(m_vertexArray[(*itTri)[i]]);
347
348                         itPV = std::find_if(p3.m_points.begin(), p3.m_points.end(), compare);
349
350                         if (itPV == p3.m_points.end())
351                         {
352                                 // add it now
353                                 p3Poly.m_indices[i] = p3.m_points.size();
354                                 p3.m_points.push_back(m_vertexArray[(*itTri)[i]]);
355                         }
356                         else
357                         {
358                                 p3Poly.m_indices[i] = std::distance(p3.m_points.begin(), itPV);
359                         }
360
361 #pragma message "unfinished"
362                         // TODO: deal with UV animation
363                         p3UV.u() = m_textureArrays[0][(*itTri)[i]].u();
364                         p3UV.v() = m_textureArrays[0][(*itTri)[i]].v();
365                         p3Poly.m_texCoords[i] = p3UV;
366                 }
367                 p3.m_polygons.push_back(p3Poly);
368         }
369
370         return p3;
371 }
372
373 bool Mesh::read(std::istream& in)
374 {
375         std::string str;
376         unsigned i,j,vertices,indices;
377         GLfloat f;
378
379         clear();
380
381         in >> str >> m_name;
382         if (in.fail() || str.compare("MESH") != 0)
383         {
384                 std::cerr << "Mesh::read - Expected MESH directive found " << str;
385                 clear();
386                 return false;
387         }
388
389         if (!isValidWzName(m_name))
390         {
391                 std::cerr << "Mesh::read - Invalid Mesh name.";
392                 m_name = std::string();
393         }
394
395         in >> str >> m_teamColours;
396         if (in.fail() || str.compare("TEAMCOLOURS") != 0)
397         {
398                 std::cerr << "Mesh::read - Expected TEAMCOLOURS directive found " << str;
399                 clear();
400                 return false;
401         }
402
403         in >> str >> vertices;
404         if (in.fail() || str.compare("VERTICES") != 0)
405         {
406                 std::cerr << "Mesh::read - Expected VERTICES directive found " << str;
407                 clear();
408                 return false;
409         }
410
411         in >> str >> indices;
412         if (in.fail() || str.compare("FACES") != 0)
413         {
414                 std::cerr << "Mesh::read - Expected FACES directive found " << str;
415                 clear();
416                 return false;
417         }
418
419         in >> str;
420         if (str.compare("VERTEXARRAY") !=0)
421         {
422                 std::cerr << "Mesh::read - Expected VERTEXARRAY directive found " << str;
423                 clear();
424                 return false;
425         }
426
427         m_vertexArray.reserve(vertices);
428         for (; vertices > 0; --vertices)
429         {
430                 WZMVertex vert;
431                 in >> vert.x() >> vert.y() >> vert.z();
432                 if (in.fail())
433                 {
434                         std::cerr << "Mesh::read - Error reading number of faces";
435                         clear();
436                         return false;
437                 }
438                 m_vertexArray.push_back(vert);
439         }
440
441         in >> str >> i;
442         if (in.fail() || str.compare("TEXTUREARRAYS") != 0)
443         {
444                 std::cerr << "Mesh::read - Expected TEXTUREARRAYS directive found " << str;
445                 clear();
446                 return false;
447         }
448
449         m_vertexArray.reserve(i);
450         for (; i > 0; --i)
451         {
452                 std::vector<WZMUV> tmp;
453                 tmp.clear();
454
455                 // j is currently ignored
456                 in >> str >> j;
457                 if ( in.fail() || str.compare("TEXTUREARRAY") != 0)
458                 {
459                         std::cerr << "Mesh::read - Expected TEXTUREARRAY directive found " << str;
460                         clear();
461                         return false;
462                 }
463
464                 for (j = 0; j < m_vertexArray.size(); ++j)
465                 {
466                         WZMUV uv;
467                         in >> uv.u() >> uv.v();
468                         if (in.fail())
469                         {
470                                 std::cerr << "Mesh::read - Error reading uv coords.";
471                                 clear();
472                                 return false;
473                         }
474                         else if(uv.u()>1||uv.v()>1)
475                         {
476                                 std::cerr << "Mesh::read - Error uv coords out of range";
477                                 clear();
478                                 return false;
479                         }
480                         tmp.push_back(uv);
481                 }
482                 m_textureArrays.push_back(tmp);
483         }
484
485         in >> str;
486         if (str.compare("INDEXARRAY") != 0)
487         {
488                 std::cerr << "Mesh::read - Expected INDEXARRAY directive found " << str;
489                 clear();
490                 return false;
491         }
492
493         m_indexArray.reserve(indices);
494         for(;indices>0;indices--)
495         {
496                 IndexedTri tri;
497
498                 in >> tri.a() >> tri.b() >> tri.c();
499
500                 if (in.fail())
501                 {
502                         std::cerr << "Mesh::read - Error reading indices";
503                         clear();
504                         return false;
505                 }
506                 m_indexArray.push_back(tri);
507         }
508
509         in >> str >> i;
510         if (in.fail() || str.compare("FRAMES") != 0)
511         {
512                 std::cerr << "Mesh::read - Expected FRAMES directive found " << str;
513                 clear();
514                 return false;
515         }
516
517         if (i > 0)
518         {
519                 // TODO: animation frames
520 #pragma message "unfinished"
521                 for(; i > 0; --i)
522                 {
523                         in >> f >> f >> f >> f >> f >> f >> f >> f;
524                 }
525                 if (in.fail())
526                 {
527                         std::cerr << "Mesh::read - Error reading frames";
528                         clear();
529                         return false;
530                 }
531         }
532
533         in >> str >> i;
534         if (in.fail() || str.compare("CONNECTORS") != 0)
535         {
536                 std::cerr << "Mesh::read - Expected CONNECTORS directive found " << str;
537                 clear();
538                 return false;
539         }
540
541         if ( i > 0)
542         {
543                 // TODO: Connectors
544 #pragma message "unfinished"
545                 for(; i > 0; --i)
546                 {
547                         in >> str >> f >> f >> f >> f >> f >> f ;
548                 }
549                 if(in.fail())
550                 {
551                         std::cerr << "Mesh::read - Error reading connectors";
552                         clear();
553                         return false;
554                 }
555         }
556
557         return true;
558 }
559
560 void Mesh::write(std::ostream &out) const
561 {
562         out << "MESH ";
563         if (m_name.empty())
564         {
565                 out << "_noname_\n";
566         }
567         else
568         {
569                 out << m_name << '\n';
570         }
571
572         // noboolalpha should be default...
573         out << "TEAMCOLOURS " << std::noboolalpha << teamColours() << '\n';
574
575         out << "VERTICES " << vertices() << '\n';
576         out << "FACES " << faces() << '\n';
577         out << "VERTEXARRAY\n" ;
578
579         std::vector<WZMVertex>::const_iterator vertIt;
580         for (vertIt=m_vertexArray.begin(); vertIt < m_vertexArray.end(); vertIt++ )
581         {
582                 out << '\t';
583                 out             << vertIt->x() << ' '
584                                 << vertIt->y() << ' '
585                                 << vertIt->z() << '\n';
586         }
587
588         out << "TEXTUREARRAYS " << textureArrays() << '\n';
589
590         std::vector< std::vector<WZMUV> >::const_iterator texArrIt;
591         for (texArrIt=m_textureArrays.begin(); texArrIt < m_textureArrays.end(); texArrIt++ )
592         {
593                 out << "TEXTUREARRAY " << std::distance(m_textureArrays.begin(),texArrIt) << '\n';
594                 std::vector<WZMUV>::const_iterator texIt;
595                 for (texIt=texArrIt->begin(); texIt < texArrIt->end(); texIt++ )
596                 {
597                         out << '\t';
598                         out     << texIt->u() << ' '
599                                         << texIt->v() << '\n';
600                 }
601         }
602
603         out << "INDEXARRAY\n";
604
605         std::vector<IndexedTri>::const_iterator indIt;
606         for (indIt=m_indexArray.begin(); indIt < m_indexArray.end(); indIt++ )
607         {
608                 out << '\t';
609                 out             << indIt->a() << ' '
610                                 << indIt->b() << ' '
611                                 << indIt->c() << '\n';
612         }
613
614         // TODO: Frames and connectors
615 #pragma message "unfinished"
616         out <<"FRAMES 0\nCONNECTORS 0\n";
617 }
618
619 bool Mesh::importFromOBJ(const std::vector<OBJTri>&     faces,
620                                                  const std::vector<OBJVertex>& verts,
621                                                  const std::vector<OBJUV>&      uvArray)
622 {
623         const WZMVertex::less_wEps vertLess; // For make_mypair
624         const WZMUV::less_wEps uvLess;
625
626         typedef std::set<mypair<WZMVertex, WZMUV,
627                 WZMVertex::less_wEps, WZMUV::less_wEps> > t_pairSet;
628
629         t_pairSet pairSet;
630
631         std::vector<OBJTri>::const_iterator itF;
632
633         std::pair<t_pairSet::iterator, bool> inResult;
634
635         std::vector<unsigned> mapping;
636         std::vector<unsigned>::iterator itMap;
637
638         unsigned i;
639
640         IndexedTri tmpTri;
641         WZMUV tmpUv;
642
643         clear();
644
645         m_textureArrays.push_back(TexArray());
646
647         for (itF = faces.begin(); itF != faces.end(); ++itF)
648         {
649                 for (i = 0; i < 3; ++i)
650                 {
651                         /* in the uv's, -1 is "not specified," but the OBJ indices
652                          * are 0 based, hence < 1
653                          */
654                         if (itF->uvs.operator [](i) < 1)
655                         {
656                                 tmpUv.u() = 0;
657                                 tmpUv.v() = 0;
658                         }
659                         else
660                         {
661                                 tmpUv = uvArray[itF->uvs.operator [](i)-1];
662                         }
663                         inResult = pairSet.insert(make_mypair(verts[itF->tri[i]-1],
664                                                                                                   tmpUv,
665                                                                                                   vertLess,
666                                                                                                   uvLess));
667
668                         if (!inResult.second)
669                         {
670                                 tmpTri[i] = mapping[std::distance(pairSet.begin(), inResult.first)];
671                         }
672                         else
673                         {
674                                 itMap = mapping.begin();
675                                 std::advance(itMap, std::distance(pairSet.begin(), inResult.first));
676                                 mapping.insert(itMap, m_vertexArray.size());
677                                 tmpTri[i] = m_vertexArray.size();
678                                 m_vertexArray.push_back(verts[itF->tri[i]-1]);
679                                 m_textureArrays[0].push_back(tmpUv);
680                         }
681                 }
682                 m_indexArray.push_back(tmpTri);
683         }
684         return true;
685 }
686
687 std::stringstream* Mesh::exportToOBJ(const Mesh_exportToOBJ_InOutParams& params) const
688 {
689         const bool invertV = true;
690         std::stringstream* out = new std::stringstream;
691
692         std::pair<std::set<OBJVertex, OBJVertex::less_wEps>::iterator, bool> vertInResult;
693         std::pair<std::set<OBJUV, OBJUV::less_wEps>::iterator, bool> uvInResult;
694
695         std::vector<IndexedTri>::const_iterator itF;
696         std::vector<unsigned>::iterator itMap;
697         unsigned i;
698
699         OBJUV uv;
700
701         *out << "o " << m_name << "\n\n";
702
703         for (itF = m_indexArray.begin(); itF != m_indexArray.end(); ++itF)
704         {
705                 *out << "f";
706
707                 for (i = 0; i < 3; ++i)
708                 {
709                         *out << ' ';
710
711                         vertInResult = params.vertSet->insert(m_vertexArray[itF->operator [](i)]);
712
713                         if (!vertInResult.second)
714                         {
715                                 *out << (*params.vertMapping)[std::distance(params.vertSet->begin(), vertInResult.first)] + 1;
716                         }
717                         else
718                         {
719                                 itMap = params.vertMapping->begin();
720                                 std::advance(itMap, std::distance(params.vertSet->begin(), vertInResult.first));
721                                 params.vertMapping->insert(itMap, params.vertices->size());
722                                 params.vertices->push_back(m_vertexArray[itF->operator [](i)]);
723                                 *out << params.vertices->size();
724                         }
725
726                         *out << '/';
727
728                         uv = m_textureArrays[0][itF->operator [](i)];
729                         if (invertV)
730                         {
731                                 uv.v() = 1 - uv.v();
732                         }
733                         uvInResult = params.uvSet->insert(uv);
734
735                         if (!uvInResult.second)
736                         {
737                                 *out << (*params.uvMapping)[std::distance(params.uvSet->begin(), uvInResult.first)] + 1;
738                         }
739                         else
740                         {
741                                 itMap = params.uvMapping->begin();
742                                 std::advance(itMap, std::distance(params.uvSet->begin(), uvInResult.first));
743                                 params.uvMapping->insert(itMap, params.uvs->size());
744                                 params.uvs->push_back(uv);
745                                 *out << params.uvs->size();
746                         }
747                 }
748                 *out << '\n';
749         }
750
751         return out;
752 }
753
754 Mesh::operator Lib3dsMesh*() const
755 {
756         const bool swapYZ = true;
757         const bool reverseWinding = true;
758         const bool invertV = true;
759
760         Lib3dsMesh* mesh;
761         unsigned i;
762
763         if (m_name.length() >= 64)
764         {
765                 char name[64];
766                 i = m_name.copy(name, 64 - 1);
767                 name[i] = '\0';
768                 mesh = lib3ds_mesh_new(name);
769         }
770         else
771         {
772                 mesh = lib3ds_mesh_new(m_name.c_str());
773         }
774
775 #ifdef LIB3DS_VERSION_1
776         lib3ds_mesh_new_point_list(mesh, m_vertexArray.size());
777         lib3ds_mesh_new_texel_list(mesh, m_vertexArray.size());
778
779         for (i = 0; i < mesh->points; ++i)
780         {
781                 if (swapYZ)
782                 {
783                         mesh->pointL[i].pos[0] = m_vertexArray[i].x();
784                         mesh->pointL[i].pos[2] = m_vertexArray[i].y();
785                         mesh->pointL[i].pos[1] = m_vertexArray[i].z();
786                 }
787                 else
788                 {
789                         mesh->pointL[i].pos[0] = m_vertexArray[i].x();
790                         mesh->pointL[i].pos[1] = m_vertexArray[i].y();
791                         mesh->pointL[i].pos[2] = m_vertexArray[i].z();
792                 }
793
794                 mesh->texelL[i][0] = m_textureArrays[0][i].u();
795                 if (invertV)
796                 {
797                         mesh->texelL[i][1] = 1.0f - m_textureArrays[0][i].v();
798                 }
799                 else
800                 {
801                         mesh->texelL[i][1] = m_textureArrays[0][i].v();
802                 }
803
804         }
805
806         lib3ds_mesh_new_face_list(mesh, m_indexArray.size());
807
808         for (i = 0; i < mesh->faces; ++i)
809         {
810                 if (reverseWinding)
811                 {
812                         mesh->faceL[i].points[2] = m_indexArray[i].a();
813                         mesh->faceL[i].points[1] = m_indexArray[i].b();
814                         mesh->faceL[i].points[0] = m_indexArray[i].c();
815                 }
816                 else
817                 {
818                         mesh->faceL[i].points[0] = m_indexArray[i].a();
819                         mesh->faceL[i].points[1] = m_indexArray[i].b();
820                         mesh->faceL[i].points[2] = m_indexArray[i].c();
821                 }
822         }
823 #else
824         lib3ds_mesh_resize_vertices(mesh, m_vertexArray.size(), 1, 0);
825
826         for (i = 0; i < mesh->nvertices; ++i)
827         {
828                 if (swapYZ)
829                 {
830                         mesh->vertices[i][0] = m_vertexArray[i].x();
831                         mesh->vertices[i][2] = m_vertexArray[i].y();
832                         mesh->vertices[i][1] = m_vertexArray[i].z();
833                 }
834                 else
835                 {
836                         mesh->vertices[i][0] = m_vertexArray[i].x();
837                         mesh->vertices[i][1] = m_vertexArray[i].y();
838                         mesh->vertices[i][2] = m_vertexArray[i].z();
839                 }
840                 
841                 mesh->texcos[i][0] = m_textureArrays[0][i].u();
842                 if (invertV)
843                 {
844                         mesh->texcos[i][1] = 1.0f - m_textureArrays[0][i].v();
845                 }
846                 else
847                 {
848                         mesh->texcos[i][1] = m_textureArrays[0][i].v();
849                 }
850                 
851         }
852
853         lib3ds_mesh_resize_faces(mesh, m_indexArray.size());
854
855         for (i = 0; i < mesh->nfaces; ++i)
856         {
857                 if (reverseWinding)
858                 {
859                         mesh->faces[i].index[2] = m_indexArray[i].a();
860                         mesh->faces[i].index[1] = m_indexArray[i].b();
861                         mesh->faces[i].index[0] = m_indexArray[i].c();
862                 }
863                 else
864                 {
865                         mesh->faces[i].index[0] = m_indexArray[i].a();
866                         mesh->faces[i].index[1] = m_indexArray[i].b();
867                         mesh->faces[i].index[2] = m_indexArray[i].c();
868                 }
869         }
870 #endif
871
872         return mesh;
873 }
874
875 std::string Mesh::getName() const
876 {
877         return m_name;
878 }
879
880 void Mesh::setName(const std::string& name)
881 {
882         if (isValidWzName(name))
883         {
884                 m_name = name;
885         }
886 }
887
888 bool Mesh::teamColours() const
889 {
890         return m_teamColours;
891 }
892
893 void Mesh::setTeamColours(bool tc)
894 {
895         m_teamColours = tc;
896 }
897
898 WZMConnector& Mesh::getConnector(int index)
899 {
900         std::list<WZMConnector>::iterator pos;
901         std::advance(pos, index);
902         return *pos;
903 }
904
905 void Mesh::addConnector (const WZMConnector& conn)
906 {
907         m_connectors.push_back(conn);
908 }
909
910 void Mesh::rmConnector (int index)
911 {
912         int i;
913         std::list<WZMConnector>::iterator pos;
914         for(i=0,pos=m_connectors.begin();i<index;i++,pos++);
915         if(pos==m_connectors.end())
916         {
917                 return;
918         }
919         m_connectors.erase(pos);
920 }
921
922 int Mesh::connectors() const
923 {
924         return m_connectors.size();
925 }
926
927 int Mesh::textureArrays() const
928 {
929         return m_textureArrays.size();
930 }
931
932 const TexArray& Mesh::getTexArray (int index) const
933 {
934         return m_textureArrays.at(index);
935 }
936
937 #if 0
938 void Mesh::addTexArray (const TexArray& tex, int index)
939 {
940         if(tex.size()!=indices())
941         {
942                 return;
943         }
944         m_textureArrays.insert(m_textureArrays.begin() + index,tex);
945 }
946 #endif
947 #if 0
948 void Mesh::rmTexArray(int index)
949 {
950         std::vector<TexArray>::iterator pos;
951         pos=m_textureArrays.begin()+index;
952         if(pos==m_textureArrays.end())
953         {
954                 return;
955         }
956         m_textureArrays.erase(pos);
957 }
958 #endif
959
960 unsigned Mesh::vertices() const
961 {
962         return m_vertexArray.size();
963 }
964
965 unsigned Mesh::faces() const
966 {
967         return triangles();
968 }
969
970 unsigned Mesh::triangles() const
971 {
972         return m_indexArray.size();
973 }
974
975 unsigned Mesh::frames() const
976 {
977         return m_frameArray.size();
978 }
979
980 unsigned Mesh::indices() const
981 {
982         return m_indexArray.size();
983 }
984
985 bool Mesh::isValid() const
986 {
987         // TODO: check m_frameArray, m_connectors
988 #pragma message "unfinished"
989         if (!isValidWzName(m_name))
990         {
991                 return false;
992         }
993
994         // Check that the values of the indices are in range
995         std::vector<IndexedTri>::const_iterator it;
996         for (it = m_indexArray.begin(); it != m_indexArray.end(); ++it)
997         {
998                 if ((*it).a() >= m_vertexArray.size())
999                 {
1000                         return false;
1001                 }
1002                 if ((*it).b() >= m_vertexArray.size())
1003                 {
1004                         return false;
1005                 }
1006                 if ((*it).c() >= m_vertexArray.size())
1007                 {
1008                         return false;
1009                 }
1010         }
1011         return true;
1012 }
1013
1014 void Mesh::defaultConstructor()
1015 {
1016         m_name = std::string();
1017         m_teamColours = false;
1018 }
1019
1020 void Mesh::clear()
1021 {
1022         m_name = std::string();
1023         m_frameArray.clear();
1024         m_vertexArray.clear();
1025         m_textureArrays.clear();
1026         m_indexArray.clear();
1027         m_connectors.clear();
1028         m_teamColours = false;
1029 }
1030
1031 void Mesh::scale(GLfloat x, GLfloat y, GLfloat z)
1032 {
1033         std::vector<WZMVertex>::iterator vertIt;
1034         for (vertIt = m_vertexArray.begin(); vertIt < m_vertexArray.end(); ++vertIt )
1035         {
1036                 vertIt->scale(x, y, z);
1037         }
1038
1039 #pragma message "TODO: Mesh::scale - Frames and connectors"
1040 }