2 Copyright (C) 2001-2006, William Joseph.
3 Copyright (C) 2010-2014 COR Entertainment, LLC.
6 This file is part of GtkRadiant.
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.
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.
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
25 #include "ifilesystem.h"
29 #include "bytestreamutils.h"
31 #include "../md3model/model.h"
33 typedef unsigned char byte;
36 ========================================================================
38 .IQM triangle model file format
40 ========================================================================
48 void istream_read_iqmSt(PointerInputStream& inputStream, iqmSt_t& st)
50 st.s = istream_read_float32_le(inputStream);
51 st.t = istream_read_float32_le(inputStream);
56 unsigned int indices[3];
59 void istream_read_iqmTriangle(PointerInputStream& inputStream, iqmTriangle_t& triangle)
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);
71 void istream_read_iqmPos(PointerInputStream& inputStream, iqmPos_t& iqmPos)
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);
78 #define IQM_POSITION 0
79 #define IQM_TEXCOORD 1
82 #define IQM_BLENDINDEXES 4
83 #define IQM_BLENDWEIGHTS 5
85 #define IQM_CUSTOM 0x10
100 typedef struct iqmHeader_s
103 unsigned int version;
104 unsigned int filesize;
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;
118 void istream_read_iqmHeader(PointerInputStream& inputStream, iqmHeader_t& header)
120 inputStream.read(header.id, 16);
121 #define READINT(x) header.x = istream_read_int32_le(inputStream);
129 READINT (num_vertexarrays)
130 READINT (num_vertexes)
131 READINT (ofs_vertexarrays)
132 READINT (num_triangles)
133 READINT (ofs_triangles)
134 READINT (ofs_neighbors)
138 READINT (num_framechannels)
141 READINT (num_comment)
142 READINT (ofs_comment)
143 READINT (num_extensions)
144 READINT (ofs_extensions)
148 typedef struct iqmvertexarray_s
158 void istream_read_iqmVertexarray(PointerInputStream& inputStream, iqmvertexarray_t& out)
160 #define READINT(x) out.x = istream_read_int32_le(inputStream);
170 ArbitraryMeshVertex IQMVertex_construct(const iqmPos_t* pos, const iqmPos_t* norm, const iqmSt_t* st)
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)
179 void IQMSurface_read(Model& model, const byte* buffer, ArchiveFile& file)
181 Surface& surface = model.newSurface();
184 PointerInputStream inputStream(buffer);
185 istream_read_iqmHeader(inputStream, header);
190 UniqueVertexBuffer<ArbitraryMeshVertex> inserter(surface.vertices());
191 inserter.reserve(header.num_vertexes);
193 int ofs_position = -1, ofs_st = -1, ofs_normal = -1;
194 PointerInputStream vaStream (buffer + header.ofs_vertexarrays);
195 for (int i = 0; i < header.num_vertexarrays; i++)
198 istream_read_iqmVertexarray (vaStream, va);
203 if (va.format == IQM_FLOAT && va.size == 3)
204 ofs_position = va.offset;
207 if (va.format == IQM_FLOAT && va.size == 2)
211 if (va.format == IQM_FLOAT && va.size == 3)
212 ofs_normal = va.offset;
217 surface.indices().reserve(header.num_vertexes);
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)
223 istream_read_iqmPos(posStream, *i);
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)
230 istream_read_iqmPos(normStream, *i);
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)
237 istream_read_iqmSt(stStream, *i);
240 PointerInputStream triangleStream(buffer + header.ofs_triangles);
241 for(int i = 0; i < header.num_triangles; ++i)
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]])));
253 surface.setShader("");
254 surface.updateAABB();
257 void IQMModel_read(Model& model, const byte* buffer, ArchiveFile& file)
259 IQMSurface_read(model, buffer, file);
263 scene::Node& IQMModel_new(const byte* buffer, ArchiveFile& file)
265 ModelNode* modelNode = new ModelNode();
266 IQMModel_read(modelNode->model(), buffer, file);
267 return modelNode->node();
270 scene::Node& IQMModel_default()
272 ModelNode* modelNode = new ModelNode();
273 Model_constructNull(modelNode->model());
274 return modelNode->node();
277 scene::Node& IQMModel_fromBuffer(unsigned char* buffer, ArchiveFile& file)
279 if (memcmp(buffer, "INTERQUAKEMODEL", 16))
281 globalErrorStream() << "IQM read error: incorrect ident\n";
282 return IQMModel_default();
286 return IQMModel_new(buffer, file);
290 scene::Node& loadIQMModel(ArchiveFile& file)
292 ScopedArchiveBuffer buffer(file);
293 return IQMModel_fromBuffer(buffer.buffer, file);