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 ){
49 st.s = istream_read_float32_le( inputStream );
50 st.t = istream_read_float32_le( inputStream );
54 unsigned int indices[3];
57 void istream_read_iqmTriangle( PointerInputStream &inputStream, iqmTriangle_t &triangle ){
58 triangle.indices[0] = istream_read_int32_le( inputStream );
59 triangle.indices[1] = istream_read_int32_le( inputStream );
60 triangle.indices[2] = istream_read_int32_le( inputStream );
67 void istream_read_iqmPos( PointerInputStream &inputStream, iqmPos_t &iqmPos ){
68 iqmPos.v[0] = istream_read_float32_le( inputStream );
69 iqmPos.v[1] = istream_read_float32_le( inputStream );
70 iqmPos.v[2] = istream_read_float32_le( inputStream );
73 const int IQM_POSITION = 0;
74 const int IQM_TEXCOORD = 1;
75 const int IQM_NORMAL = 2;
76 const int IQM_TANGENT = 3;
77 const int IQM_BLENDINDEXES = 4;
78 const int IQM_BLENDWEIGHTS = 5;
79 const int IQM_COLOR = 6;
80 const int IQM_CUSTOM = 0x10;
82 const int IQM_BYTE = 0;
83 const int IQM_UBYTE = 1;
84 const int IQM_SHORT = 2;
85 const int IQM_USHORT = 3;
86 const int IQM_INT = 4;
87 const int IQM_UINT = 5;
88 const int IQM_HALF = 6;
89 const int IQM_FLOAT = 7;
90 const int IQM_DOUBLE = 8;
93 const int IQM_LOOP = 1;
95 typedef struct iqmHeader_s {
98 unsigned int filesize;
100 unsigned int num_text, ofs_text;
101 unsigned int num_meshes, ofs_meshes;
102 unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
103 unsigned int num_triangles, ofs_triangles, ofs_neighbors;
104 unsigned int num_joints, ofs_joints;
105 unsigned int num_poses, ofs_poses;
106 unsigned int num_anims, ofs_anims;
107 unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
108 unsigned int num_comment, ofs_comment;
109 unsigned int num_extensions, ofs_extensions;
112 void istream_read_iqmHeader( PointerInputStream &inputStream, iqmHeader_t &header ){
113 inputStream.read( header.id, 16 );
114 #define READINT( x ) header.x = istream_read_int32_le( inputStream );
120 READINT( num_meshes )
121 READINT( ofs_meshes )
122 READINT( num_vertexarrays )
123 READINT( num_vertexes )
124 READINT( ofs_vertexarrays )
125 READINT( num_triangles )
126 READINT( ofs_triangles )
127 READINT( ofs_neighbors )
128 READINT( num_joints )
129 READINT( ofs_joints )
130 READINT( num_frames )
131 READINT( num_framechannels )
132 READINT( ofs_frames )
133 READINT( ofs_bounds )
134 READINT( num_comment )
135 READINT( ofs_comment )
136 READINT( num_extensions )
137 READINT( ofs_extensions )
141 typedef struct iqmmesh_s {
143 unsigned int material;
144 unsigned int first_vertex;
145 unsigned int num_vertexes;
146 unsigned int first_triangle;
147 unsigned int num_triangles;
150 void istream_read_iqmMesh( PointerInputStream &inputStream, iqmmesh_t &iqmmesh ){
151 #define READUINT( x ) iqmmesh.x = istream_read_uint32_le( inputStream );
154 READUINT( first_vertex )
155 READUINT( num_vertexes )
156 READUINT( first_triangle )
157 READUINT( num_triangles )
161 typedef struct iqmvertexarray_s {
169 void istream_read_iqmVertexarray( PointerInputStream &inputStream, iqmvertexarray_t &vertexarray ){
170 #define READINT( x ) vertexarray.x = istream_read_int32_le( inputStream );
179 typedef struct iqmvertex_s {
184 unsigned char blendindices[4];
185 unsigned char blendweights[4];
186 unsigned char color[4];
189 ArbitraryMeshVertex IQMVertex_construct( const iqmPos_t *pos, const iqmPos_t *norm, const iqmSt_t *st ){
190 return ArbitraryMeshVertex(
191 Vertex3f( pos->v[0], pos->v[1], pos->v[2] ),
192 Normal3f( norm->v[0], norm->v[1], norm->v[2] ),
193 TexCoord2f( st->s, st->t )
197 void IQMSurface_read( Model &model, const byte *buffer, ArchiveFile &file ){
200 PointerInputStream inputStream( buffer );
201 istream_read_iqmHeader( inputStream, header );
204 printf( "num meshes: %d\n", header.num_meshes );
206 int ofs_position = -1, ofs_st = -1, ofs_normal = -1;
207 PointerInputStream vaStream( buffer + header.ofs_vertexarrays );
208 for ( unsigned int i = 0; i < header.num_vertexarrays; i++ ) {
210 istream_read_iqmVertexarray( vaStream, va );
214 if ( va.format == IQM_FLOAT && va.size == 3 ) {
215 ofs_position = va.offset;
219 if ( va.format == IQM_FLOAT && va.size == 2 ) {
224 if ( va.format == IQM_FLOAT && va.size == 3 ) {
225 ofs_normal = va.offset;
231 PointerInputStream posStream( buffer + ofs_position );
232 Array<iqmPos_t> iqmPos( header.num_vertexes );
233 for ( Array<iqmPos_t>::iterator i = iqmPos.begin(); i != iqmPos.end(); ++i ) {
234 istream_read_iqmPos( posStream, *i );
237 PointerInputStream normStream( buffer + ofs_normal );
238 Array<iqmPos_t> iqmNorm( header.num_vertexes );
239 for ( Array<iqmPos_t>::iterator i = iqmNorm.begin(); i != iqmNorm.end(); ++i ) {
240 istream_read_iqmPos( normStream, *i );
243 Array<iqmSt_t> iqmSt( header.num_vertexes );
244 PointerInputStream stStream( buffer + ofs_st );
245 for ( Array<iqmSt_t>::iterator i = iqmSt.begin(); i != iqmSt.end(); ++i ) {
246 istream_read_iqmSt( stStream, *i );
249 PointerInputStream iqmMesh( buffer + header.ofs_meshes );
250 for ( unsigned int m = 0; m < header.num_meshes; m++ ) {
251 Surface &surface = model.newSurface();
254 istream_read_iqmMesh( iqmMesh, iqmmesh );
256 // if not malformed data neither missing string
257 if ( iqmmesh.name <= header.num_text && iqmmesh.name > 0 ) {
259 name = (char*) buffer + header.ofs_text + iqmmesh.name;
260 printf( "mesh: %d, name: %s\n", m, name );
263 bool material_found = false;
264 // if not malformed data neither missing string
265 if ( iqmmesh.material <= header.num_text && iqmmesh.material > 0 ) {
267 material = (char*) buffer + header.ofs_text + iqmmesh.material;
269 printf( "mesh: %d, texture: %s\n", m, material );
271 if ( material[0] != '\0' ) {
272 surface.setShader( material );
273 material_found = true;
277 if ( !material_found ) {
278 // empty string will trigger "textures/shader/notex" on display
279 surface.setShader( "" );
282 printf( "mesh: %d, num vertexes: %d\n", m, iqmmesh.num_vertexes );
283 printf( "mesh: %d, num triangles: %d\n", m, iqmmesh.num_triangles );
285 UniqueVertexBuffer<ArbitraryMeshVertex> inserter( surface.vertices() );
286 inserter.reserve( iqmmesh.num_vertexes );
288 surface.indices().reserve( iqmmesh.num_vertexes );
290 unsigned int triangle_offset = header.ofs_triangles + iqmmesh.first_triangle * sizeof( iqmTriangle_t );
291 PointerInputStream triangleStream( buffer + triangle_offset );
292 for ( unsigned int i = 0; i < iqmmesh.num_triangles; ++i ) {
293 iqmTriangle_t triangle;
294 istream_read_iqmTriangle( triangleStream, triangle );
295 for ( int j = 0; j < 3; j++ ) {
296 surface.indices().insert( inserter.insert( IQMVertex_construct(
297 &iqmPos[triangle.indices[j]],
298 &iqmNorm[triangle.indices[j]],
299 &iqmSt[triangle.indices[j]] ) ) );
303 surface.updateAABB();
307 void IQMModel_read( Model &model, const byte *buffer, ArchiveFile &file ){
308 IQMSurface_read( model, buffer, file );
312 scene::Node &IQMModel_new( const byte *buffer, ArchiveFile &file ){
313 ModelNode *modelNode = new ModelNode();
314 IQMModel_read( modelNode->model(), buffer, file );
315 return modelNode->node();
318 scene::Node &IQMModel_default(){
319 ModelNode *modelNode = new ModelNode();
320 Model_constructNull( modelNode->model() );
321 return modelNode->node();
324 scene::Node &IQMModel_fromBuffer( unsigned char *buffer, ArchiveFile &file ){
325 if ( memcmp( buffer, "INTERQUAKEMODEL", 16 ) ) {
326 globalErrorStream() << "IQM read error: incorrect ident\n";
327 return IQMModel_default();
330 return IQMModel_new( buffer, file );
334 scene::Node &loadIQMModel( ArchiveFile &file ){
335 ScopedArchiveBuffer buffer( file );
336 return IQMModel_fromBuffer( buffer.buffer, file );