2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "ifilesystem.h"
28 #include "bytestreamutils.h"
32 #include "mdlnormals.h"
34 typedef unsigned char byte;
37 ========================================================================
39 .MD2 triangle model file format
41 ========================================================================
43 const int MD2_NUMVERTEXNORMALS = 162;
45 const unsigned char MD2_IDENT[4] = { 'I', 'D', 'P', '2', };
46 const int MD2_VERSION = 8;
48 const int MD2_MAX_TRIANGLES = 4096;
49 const int MD2_MAX_VERTS = 2048;
50 const int MD2_MAX_FRAMES = 512;
51 const int MD2_MAX_MD2SKINS = 32;
52 const int MD2_MAX_SKINNAME = 64;
60 void istream_read_md2St( PointerInputStream& inputStream, md2St_t& st ){
61 st.s = istream_read_int16_le( inputStream );
62 st.t = istream_read_int16_le( inputStream );
71 void istream_read_md2Triangle( PointerInputStream& inputStream, md2Triangle_t& triangle ){
72 triangle.index_xyz[0] = istream_read_int16_le( inputStream );
73 triangle.index_xyz[1] = istream_read_int16_le( inputStream );
74 triangle.index_xyz[2] = istream_read_int16_le( inputStream );
75 triangle.index_st[0] = istream_read_int16_le( inputStream );
76 triangle.index_st[1] = istream_read_int16_le( inputStream );
77 triangle.index_st[2] = istream_read_int16_le( inputStream );
82 byte v[3]; // scaled byte to fit in frame mins/maxs
83 byte lightnormalindex;
86 void istream_read_md2XyzNormal( PointerInputStream& inputStream, md2XyzNormal_t& xyz ){
87 inputStream.read( xyz.v, 3 );
88 inputStream.read( &xyz.lightnormalindex, 1 );
91 const int MD2_XYZNORMAL_V0 = 0;
92 const int MD2_XYZNORMAL_V1 = 1;
93 const int MD2_XYZNORMAL_V2 = 2;
94 const int MD2_XYZNORMAL_LNI = 3;
95 const int MD2_XYZNORMAL_SIZE = 4;
99 float scale[3]; // multiply byte verts by this
100 float translate[3]; // then add this
101 char name[16]; // frame name from grabbing
102 md2XyzNormal_t verts[1]; // variable sized
105 void istream_read_md2Frame( PointerInputStream& inputStream, md2Frame_t& frame ){
106 frame.scale[0] = istream_read_float32_le( inputStream );
107 frame.scale[1] = istream_read_float32_le( inputStream );
108 frame.scale[2] = istream_read_float32_le( inputStream );
109 frame.translate[0] = istream_read_float32_le( inputStream );
110 frame.translate[1] = istream_read_float32_le( inputStream );
111 frame.translate[2] = istream_read_float32_le( inputStream );
112 inputStream.read( reinterpret_cast<unsigned char*>( frame.name ), 16 );
117 // a positive integer starts a tristrip command, followed by that many
118 // vertex structures.
119 // a negative integer starts a trifan command, followed by -x vertexes
120 // a zero indicates the end of the command list.
121 // a vertex consists of a floating point s, a floating point t,
122 // and an integer vertex index.
127 unsigned char ident[4];
132 int framesize; // byte size of each frame
136 int num_st; // greater than num_xyz for seams
138 int num_glcmds; // dwords in strip/fan command list
141 int ofs_skins; // each skin is a MAX_SKINNAME string
142 int ofs_st; // byte offset from start for md2St_t
143 int ofs_tris; // offset for md2triangle_t
144 int ofs_frames; // offset for first md2Frame_t
146 int ofs_end; // end of file
150 void istream_read_md2Header( PointerInputStream& inputStream, md2Header_t& header ){
151 inputStream.read( header.ident, 4 );
152 header.version = istream_read_int32_le( inputStream );
153 header.skinwidth = istream_read_int32_le( inputStream );
154 header.skinheight = istream_read_int32_le( inputStream );
155 header.framesize = istream_read_int32_le( inputStream );
156 header.num_skins = istream_read_int32_le( inputStream );
157 header.num_xyz = istream_read_int32_le( inputStream );
158 header.num_st = istream_read_int32_le( inputStream );
159 header.num_tris = istream_read_int32_le( inputStream );
160 header.num_glcmds = istream_read_int32_le( inputStream );
161 header.num_frames = istream_read_int32_le( inputStream );
162 header.ofs_skins = istream_read_int32_le( inputStream );
163 header.ofs_st = istream_read_int32_le( inputStream );
164 header.ofs_tris = istream_read_int32_le( inputStream );
165 header.ofs_frames = istream_read_int32_le( inputStream );
166 header.ofs_glcmds = istream_read_int32_le( inputStream );
167 header.ofs_end = istream_read_int32_le( inputStream );
171 ArbitraryMeshVertex MD2Vertex_construct( const md2Header_t* pHeader, const md2Frame_t* pFrame, const md2XyzNormal_t* xyz, const md2St_t* st ){
172 return ArbitraryMeshVertex(
174 xyz->v[0] * pFrame->scale[0] + pFrame->translate[0],
175 xyz->v[1] * pFrame->scale[1] + pFrame->translate[1],
176 xyz->v[2] * pFrame->scale[2] + pFrame->translate[2]
179 g_mdl_normals[xyz->lightnormalindex][0],
180 g_mdl_normals[xyz->lightnormalindex][1],
181 g_mdl_normals[xyz->lightnormalindex][2]
184 (float)st->s / pHeader->skinwidth,
185 (float)st->t / pHeader->skinheight
190 void MD2Surface_read( Model& model, const byte* buffer, ArchiveFile& file ){
191 Surface& surface = model.newSurface();
194 PointerInputStream inputStream( buffer );
195 istream_read_md2Header( inputStream, header );
201 PointerInputStream frameStream( buffer + header.ofs_frames );
202 istream_read_md2Frame( frameStream, frame );
205 surface.indices().reserve( header.num_tris * 3 );
207 Array<md2XyzNormal_t> md2Xyz( header.num_xyz );
208 for ( Array<md2XyzNormal_t>::iterator i = md2Xyz.begin(); i != md2Xyz.end(); ++i )
210 istream_read_md2XyzNormal( frameStream, *i );
213 Array<md2St_t> md2St( header.num_st );
214 PointerInputStream stStream( buffer + header.ofs_st );
215 for ( Array<md2St_t>::iterator i = md2St.begin(); i != md2St.end(); ++i )
217 istream_read_md2St( stStream, *i );
220 UniqueVertexBuffer<ArbitraryMeshVertex> inserter( surface.vertices() );
221 inserter.reserve( header.num_st );
223 PointerInputStream triangleStream( buffer + header.ofs_tris );
224 for ( int i = 0; i < header.num_tris; ++i )
226 md2Triangle_t triangle;
227 istream_read_md2Triangle( triangleStream, triangle );
228 surface.indices().insert( inserter.insert( MD2Vertex_construct( &header, &frame, &md2Xyz[triangle.index_xyz[0]], &md2St[triangle.index_st[0]] ) ) );
229 surface.indices().insert( inserter.insert( MD2Vertex_construct( &header, &frame, &md2Xyz[triangle.index_xyz[1]], &md2St[triangle.index_st[1]] ) ) );
230 surface.indices().insert( inserter.insert( MD2Vertex_construct( &header, &frame, &md2Xyz[triangle.index_xyz[2]], &md2St[triangle.index_st[2]] ) ) );
234 char skinname[MD2_MAX_SKINNAME];
235 char skinnameRelative[MD2_MAX_SKINNAME];
236 char path[MD2_MAX_SKINNAME];
237 int i = MD2_MAX_SKINNAME;
238 PointerInputStream inputStream( buffer + header.ofs_skins );
239 inputStream.read( reinterpret_cast<byte*>( skinnameRelative ), MD2_MAX_SKINNAME );
240 // relative texture path - allows moving of models in game dir structure without changing the skinpath
241 // e.g. used in ufo:ai
242 if ( skinnameRelative[0] == '.' ) {
243 strncpy( path, file.getName(), MD2_MAX_SKINNAME );
247 if ( path[i] == '/' || path[i] == '\\' ) {
252 // globalErrorStream() << "modified skinname: " << path << " (path) and " << skinnameRelative << " (texture)" << "\n";
253 snprintf( skinname, MD2_MAX_SKINNAME, "%s%s", path, &skinnameRelative[1] );
254 // globalErrorStream() << skinname << "\n";
258 strcpy( skinname, skinnameRelative );
260 surface.setShader( skinname );
261 surface.updateAABB();
264 void MD2Model_read( Model& model, const byte* buffer, ArchiveFile& file ){
265 MD2Surface_read( model, buffer, file );
269 scene::Node& MD2Model_new( const byte* buffer, ArchiveFile& file ){
270 ModelNode* modelNode = new ModelNode();
271 MD2Model_read( modelNode->model(), buffer, file );
272 return modelNode->node();
275 scene::Node& MD2Model_default(){
276 ModelNode* modelNode = new ModelNode();
277 Model_constructNull( modelNode->model() );
278 return modelNode->node();
281 scene::Node& MD2Model_fromBuffer( unsigned char* buffer, ArchiveFile& file ){
282 if ( !ident_equal( buffer, MD2_IDENT ) ) {
283 globalErrorStream() << "MD2 read error: incorrect ident\n";
284 return MD2Model_default();
288 return MD2Model_new( buffer, file );
292 scene::Node& loadMD2Model( ArchiveFile& file ){
293 ScopedArchiveBuffer buffer( file );
294 return MD2Model_fromBuffer( buffer.buffer, file );