]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/iqmmodel/iqm.cpp
reformat code! now the code is only ugly on the *inside*
[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     float s;
44     float t;
45 } iqmSt_t;
46
47 void istream_read_iqmSt(PointerInputStream &inputStream, iqmSt_t &st)
48 {
49     st.s = istream_read_float32_le(inputStream);
50     st.t = istream_read_float32_le(inputStream);
51 }
52
53 typedef struct {
54     unsigned int indices[3];
55 } iqmTriangle_t;
56
57 void istream_read_iqmTriangle(PointerInputStream &inputStream, iqmTriangle_t &triangle)
58 {
59     triangle.indices[0] = istream_read_int32_le(inputStream);
60     triangle.indices[1] = istream_read_int32_le(inputStream);
61     triangle.indices[2] = istream_read_int32_le(inputStream);
62 }
63
64 typedef struct {
65     float v[3];
66 } iqmPos_t;
67
68 void istream_read_iqmPos(PointerInputStream &inputStream, iqmPos_t &iqmPos)
69 {
70     iqmPos.v[0] = istream_read_float32_le(inputStream);
71     iqmPos.v[1] = istream_read_float32_le(inputStream);
72     iqmPos.v[2] = istream_read_float32_le(inputStream);
73 }
74
75 const int IQM_POSITION = 0;
76 const int IQM_TEXCOORD = 1;
77 const int IQM_NORMAL = 2;
78 const int IQM_TANGENT = 3;
79 const int IQM_BLENDINDEXES = 4;
80 const int IQM_BLENDWEIGHTS = 5;
81 const int IQM_COLOR = 6;
82 const int IQM_CUSTOM = 0x10;
83
84 const int IQM_BYTE = 0;
85 const int IQM_UBYTE = 1;
86 const int IQM_SHORT = 2;
87 const int IQM_USHORT = 3;
88 const int IQM_INT = 4;
89 const int IQM_UINT = 5;
90 const int IQM_HALF = 6;
91 const int IQM_FLOAT = 7;
92 const int IQM_DOUBLE = 8;
93
94 // animflags
95 const int IQM_LOOP = 1;
96
97 typedef struct iqmHeader_s {
98     byte id[16];
99     unsigned int version;
100     unsigned int filesize;
101     unsigned int flags;
102     unsigned int num_text, ofs_text;
103     unsigned int num_meshes, ofs_meshes;
104     unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
105     unsigned int num_triangles, ofs_triangles, ofs_neighbors;
106     unsigned int num_joints, ofs_joints;
107     unsigned int num_poses, ofs_poses;
108     unsigned int num_anims, ofs_anims;
109     unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
110     unsigned int num_comment, ofs_comment;
111     unsigned int num_extensions, ofs_extensions;
112 } iqmHeader_t;
113
114 void istream_read_iqmHeader(PointerInputStream &inputStream, iqmHeader_t &header)
115 {
116     inputStream.read(header.id, 16);
117 #define READINT(x) header.x = istream_read_int32_le(inputStream);
118     READINT (version)
119     READINT (filesize)
120     READINT (flags)
121     READINT (num_text)
122     READINT (ofs_text)
123     READINT (num_meshes)
124     READINT (ofs_meshes)
125     READINT (num_vertexarrays)
126     READINT (num_vertexes)
127     READINT (ofs_vertexarrays)
128     READINT (num_triangles)
129     READINT (ofs_triangles)
130     READINT (ofs_neighbors)
131     READINT (num_joints)
132     READINT (ofs_joints)
133     READINT (num_frames)
134     READINT (num_framechannels)
135     READINT (ofs_frames)
136     READINT (ofs_bounds)
137     READINT (num_comment)
138     READINT (ofs_comment)
139     READINT (num_extensions)
140     READINT (ofs_extensions)
141 #undef READINT
142 }
143
144 typedef struct iqmvertexarray_s {
145     unsigned int type;
146     unsigned int flags;
147     unsigned int format;
148     unsigned int size;
149     unsigned int offset;
150 }
151         iqmvertexarray_t;
152
153 void istream_read_iqmVertexarray(PointerInputStream &inputStream, iqmvertexarray_t &out)
154 {
155 #define READINT(x) out.x = istream_read_int32_le(inputStream);
156     READINT (type)
157     READINT (flags)
158     READINT (format)
159     READINT (size)
160     READINT (offset)
161 #undef READINT
162 }
163
164
165 ArbitraryMeshVertex IQMVertex_construct(const iqmPos_t *pos, const iqmPos_t *norm, const iqmSt_t *st)
166 {
167     return ArbitraryMeshVertex(
168             Vertex3f(pos->v[0], pos->v[1], pos->v[2]),
169             Normal3f(norm->v[0], norm->v[1], norm->v[2]),
170             TexCoord2f(st->s, st->t)
171     );
172 }
173
174 void IQMSurface_read(Model &model, const byte *buffer, ArchiveFile &file)
175 {
176     Surface &surface = model.newSurface();
177     iqmHeader_t header;
178     {
179         PointerInputStream inputStream(buffer);
180         istream_read_iqmHeader(inputStream, header);
181     }
182
183     {
184
185         UniqueVertexBuffer<ArbitraryMeshVertex> inserter(surface.vertices());
186         inserter.reserve(header.num_vertexes);
187
188         int ofs_position = -1, ofs_st = -1, ofs_normal = -1;
189         PointerInputStream vaStream(buffer + header.ofs_vertexarrays);
190         for (unsigned int i = 0; i < header.num_vertexarrays; i++) {
191             iqmvertexarray_t va;
192             istream_read_iqmVertexarray(vaStream, va);
193
194             switch (va.type) {
195                 case IQM_POSITION:
196                     if (va.format == IQM_FLOAT && va.size == 3) {
197                         ofs_position = va.offset;
198                     }
199                     break;
200                 case IQM_TEXCOORD:
201                     if (va.format == IQM_FLOAT && va.size == 2) {
202                         ofs_st = va.offset;
203                     }
204                     break;
205                 case IQM_NORMAL:
206                     if (va.format == IQM_FLOAT && va.size == 3) {
207                         ofs_normal = va.offset;
208                     }
209                     break;
210             }
211         }
212
213         surface.indices().reserve(header.num_vertexes);
214
215         PointerInputStream posStream(buffer + ofs_position);
216         Array<iqmPos_t> iqmPos(header.num_vertexes);
217         for (Array<iqmPos_t>::iterator i = iqmPos.begin(); i != iqmPos.end(); ++i) {
218             istream_read_iqmPos(posStream, *i);
219         }
220
221         PointerInputStream normStream(buffer + ofs_normal);
222         Array<iqmPos_t> iqmNorm(header.num_vertexes);
223         for (Array<iqmPos_t>::iterator i = iqmNorm.begin(); i != iqmNorm.end(); ++i) {
224             istream_read_iqmPos(normStream, *i);
225         }
226
227         Array<iqmSt_t> iqmSt(header.num_vertexes);
228         PointerInputStream stStream(buffer + ofs_st);
229         for (Array<iqmSt_t>::iterator i = iqmSt.begin(); i != iqmSt.end(); ++i) {
230             istream_read_iqmSt(stStream, *i);
231         }
232
233         PointerInputStream triangleStream(buffer + header.ofs_triangles);
234         for (unsigned int i = 0; i < header.num_triangles; ++i) {
235             iqmTriangle_t triangle;
236             istream_read_iqmTriangle(triangleStream, triangle);
237             for (int j = 0; j < 3; j++) {
238                 surface.indices().insert(inserter.insert(IQMVertex_construct(
239                         &iqmPos[triangle.indices[j]],
240                         &iqmNorm[triangle.indices[j]],
241                         &iqmSt[triangle.indices[j]])));
242             }
243         }
244     }
245
246     surface.setShader("");
247     surface.updateAABB();
248 }
249
250 void IQMModel_read(Model &model, const byte *buffer, ArchiveFile &file)
251 {
252     IQMSurface_read(model, buffer, file);
253     model.updateAABB();
254 }
255
256 scene::Node &IQMModel_new(const byte *buffer, ArchiveFile &file)
257 {
258     ModelNode *modelNode = new ModelNode();
259     IQMModel_read(modelNode->model(), buffer, file);
260     return modelNode->node();
261 }
262
263 scene::Node &IQMModel_default()
264 {
265     ModelNode *modelNode = new ModelNode();
266     Model_constructNull(modelNode->model());
267     return modelNode->node();
268 }
269
270 scene::Node &IQMModel_fromBuffer(unsigned char *buffer, ArchiveFile &file)
271 {
272     if (memcmp(buffer, "INTERQUAKEMODEL", 16)) {
273         globalErrorStream() << "IQM read error: incorrect ident\n";
274         return IQMModel_default();
275     } else {
276         return IQMModel_new(buffer, file);
277     }
278 }
279
280 scene::Node &loadIQMModel(ArchiveFile &file)
281 {
282     ScopedArchiveBuffer buffer(file);
283     return IQMModel_fromBuffer(buffer.buffer, file);
284 }