Remove -Wno-sign-compare
[xonotic/netradiant.git] / plugins / iqmmodel / iqm.cpp
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 Copyright (C) 2010-2014 COR Entertainment, LLC.
4 All Rights Reserved.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 */
22
23 #include "iqm.h"
24
25 #include "ifilesystem.h"
26 #include "imodel.h"
27
28 #include "imagelib.h"
29 #include "bytestreamutils.h"
30
31 #include "../md3model/model.h"
32
33 typedef unsigned char byte;
34
35 /*
36 ========================================================================
37
38 .IQM triangle model file format
39
40 ========================================================================
41 */
42 typedef struct
43 {
44         float   s;
45         float   t;
46 } iqmSt_t;
47
48 void istream_read_iqmSt(PointerInputStream& inputStream, iqmSt_t& st)
49 {
50   st.s = istream_read_float32_le(inputStream);
51   st.t = istream_read_float32_le(inputStream);
52 }
53
54 typedef struct 
55 {
56         unsigned int indices[3];
57 } iqmTriangle_t;
58
59 void istream_read_iqmTriangle(PointerInputStream& inputStream, iqmTriangle_t& triangle)
60 {
61   triangle.indices[0] = istream_read_int32_le(inputStream);
62   triangle.indices[1] = istream_read_int32_le(inputStream);
63   triangle.indices[2] = istream_read_int32_le(inputStream);
64 }
65
66 typedef struct
67 {
68         float   v[3];
69 } iqmPos_t;
70
71 void istream_read_iqmPos(PointerInputStream& inputStream, iqmPos_t& iqmPos)
72 {
73   iqmPos.v[0] = istream_read_float32_le(inputStream);
74   iqmPos.v[1] = istream_read_float32_le(inputStream);
75   iqmPos.v[2] = istream_read_float32_le(inputStream);
76 }
77
78 #define IQM_POSITION        0
79 #define IQM_TEXCOORD        1
80 #define IQM_NORMAL          2
81 #define IQM_TANGENT         3
82 #define IQM_BLENDINDEXES    4
83 #define IQM_BLENDWEIGHTS    5
84 #define IQM_COLOR               6
85 #define IQM_CUSTOM          0x10
86
87 #define IQM_BYTE    0
88 #define IQM_UBYTE   1
89 #define IQM_SHORT   2
90 #define IQM_USHORT  3
91 #define IQM_INT     4
92 #define IQM_UINT    5
93 #define IQM_HALF    6
94 #define IQM_FLOAT   7
95 #define IQM_DOUBLE  8
96
97 // animflags
98 #define IQM_LOOP 1
99
100 typedef struct iqmHeader_s
101 {
102         byte id[16];
103         unsigned int version;
104         unsigned int filesize;
105         unsigned int flags;
106         unsigned int num_text, ofs_text;
107         unsigned int num_meshes, ofs_meshes;
108         unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
109         unsigned int num_triangles, ofs_triangles, ofs_neighbors;
110         unsigned int num_joints, ofs_joints;
111         unsigned int num_poses, ofs_poses;
112         unsigned int num_anims, ofs_anims;
113         unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
114         unsigned int num_comment, ofs_comment;
115         unsigned int num_extensions, ofs_extensions;
116 } iqmHeader_t;
117
118 void istream_read_iqmHeader(PointerInputStream& inputStream, iqmHeader_t& header)
119 {
120   inputStream.read(header.id, 16);
121 #define READINT(x) header.x = istream_read_int32_le(inputStream);
122   READINT (version)
123   READINT (filesize)
124   READINT (flags)
125   READINT (num_text)
126   READINT (ofs_text)
127   READINT (num_meshes)
128   READINT (ofs_meshes)
129   READINT (num_vertexarrays)
130   READINT (num_vertexes)
131   READINT (ofs_vertexarrays)
132   READINT (num_triangles)
133   READINT (ofs_triangles)
134   READINT (ofs_neighbors)
135   READINT (num_joints)
136   READINT (ofs_joints)
137   READINT (num_frames)
138   READINT (num_framechannels)
139   READINT (ofs_frames)
140   READINT (ofs_bounds)
141   READINT (num_comment)
142   READINT (ofs_comment)
143   READINT (num_extensions)
144   READINT (ofs_extensions)
145 #undef READINT
146 }
147
148 typedef struct iqmvertexarray_s
149 {
150         unsigned int type;
151         unsigned int flags;
152         unsigned int format;
153         unsigned int size;
154         unsigned int offset;
155 }
156 iqmvertexarray_t;
157
158 void istream_read_iqmVertexarray(PointerInputStream& inputStream, iqmvertexarray_t& out)
159 {
160 #define READINT(x) out.x = istream_read_int32_le(inputStream);
161   READINT (type)
162   READINT (flags)
163   READINT (format)
164   READINT (size)
165   READINT (offset)
166 #undef READINT
167 }
168
169
170 ArbitraryMeshVertex IQMVertex_construct(const iqmPos_t* pos, const iqmPos_t* norm, const iqmSt_t* st)
171 {
172   return ArbitraryMeshVertex(
173     Vertex3f (pos->v[0], pos->v[1], pos->v[2]),
174     Normal3f (norm->v[0], norm->v[1], norm->v[2]),
175     TexCoord2f (st->s, st->t)
176   );
177 }
178
179 void IQMSurface_read(Model& model, const byte* buffer, ArchiveFile& file)
180 {
181   Surface& surface = model.newSurface();
182   iqmHeader_t header;
183   {
184     PointerInputStream inputStream(buffer);
185     istream_read_iqmHeader(inputStream, header);
186   }
187
188   {
189
190     UniqueVertexBuffer<ArbitraryMeshVertex> inserter(surface.vertices());
191     inserter.reserve(header.num_vertexes);
192     
193     int ofs_position = -1, ofs_st = -1, ofs_normal = -1;
194     PointerInputStream vaStream (buffer + header.ofs_vertexarrays);
195     for (unsigned int i = 0; i < header.num_vertexarrays; i++)
196     {
197         iqmvertexarray_t va;
198         istream_read_iqmVertexarray (vaStream, va);
199         
200         switch (va.type)
201         {
202         case IQM_POSITION:
203             if (va.format == IQM_FLOAT && va.size == 3)
204                 ofs_position = va.offset;
205             break;
206         case IQM_TEXCOORD:
207             if (va.format == IQM_FLOAT && va.size == 2)
208                 ofs_st = va.offset;
209             break;
210         case IQM_NORMAL:
211             if (va.format == IQM_FLOAT && va.size == 3)
212                 ofs_normal = va.offset;
213             break;
214         }
215     }
216     
217     surface.indices().reserve(header.num_vertexes);
218
219     PointerInputStream posStream(buffer + ofs_position);
220     Array<iqmPos_t> iqmPos(header.num_vertexes);
221     for(Array<iqmPos_t>::iterator i = iqmPos.begin(); i != iqmPos.end(); ++i)
222     {
223       istream_read_iqmPos(posStream, *i);
224     }
225     
226     PointerInputStream normStream(buffer + ofs_normal);
227     Array<iqmPos_t> iqmNorm(header.num_vertexes);
228     for(Array<iqmPos_t>::iterator i = iqmNorm.begin(); i != iqmNorm.end(); ++i)
229     {
230       istream_read_iqmPos(normStream, *i);
231     }
232
233     Array<iqmSt_t> iqmSt(header.num_vertexes);
234     PointerInputStream stStream(buffer + ofs_st);
235     for(Array<iqmSt_t>::iterator i = iqmSt.begin(); i != iqmSt.end(); ++i)
236     {
237       istream_read_iqmSt(stStream, *i);
238     }
239     
240     PointerInputStream triangleStream(buffer + header.ofs_triangles);
241         for(unsigned int i = 0; i < header.num_triangles; ++i)
242     {
243       iqmTriangle_t triangle;
244       istream_read_iqmTriangle(triangleStream, triangle);
245       for (int j = 0; j < 3; j++)
246         surface.indices().insert(inserter.insert(IQMVertex_construct(
247             &iqmPos[triangle.indices[j]],
248             &iqmNorm[triangle.indices[j]],
249             &iqmSt[triangle.indices[j]])));
250     }
251   }
252   
253   surface.setShader("");
254   surface.updateAABB();
255 }
256
257 void IQMModel_read(Model& model, const byte* buffer, ArchiveFile& file)
258 {
259   IQMSurface_read(model, buffer, file);
260   model.updateAABB();
261 }
262
263 scene::Node& IQMModel_new(const byte* buffer, ArchiveFile& file)
264 {
265   ModelNode* modelNode = new ModelNode();
266   IQMModel_read(modelNode->model(), buffer, file);
267   return modelNode->node();
268 }
269
270 scene::Node& IQMModel_default()
271 {
272   ModelNode* modelNode = new ModelNode();
273   Model_constructNull(modelNode->model());
274   return modelNode->node();
275 }
276
277 scene::Node& IQMModel_fromBuffer(unsigned char* buffer, ArchiveFile& file)
278 {
279   if (memcmp(buffer, "INTERQUAKEMODEL", 16))
280   {
281           globalErrorStream() << "IQM read error: incorrect ident\n";
282     return IQMModel_default();
283   }
284   else
285   {
286     return IQMModel_new(buffer, file);
287   }
288 }
289
290 scene::Node& loadIQMModel(ArchiveFile& file)
291 {
292   ScopedArchiveBuffer buffer(file);
293   return IQMModel_fromBuffer(buffer.buffer, file);
294 }