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 #define MD2_NUMVERTEXNORMALS 162
44 #define MD2_MAX_SKINNAME 64
46 const unsigned char MD2_IDENT[4] = { 'I', 'D', 'P', '2', };
49 #define MD2_MAX_TRIANGLES 4096
50 #define MD2_MAX_VERTS 2048
51 #define MD2_MAX_FRAMES 512
52 #define MD2_MAX_MD2SKINS 32
53 #define MD2_MAX_SKINNAME 64
61 void istream_read_md2St( PointerInputStream& inputStream, md2St_t& st ){
62 st.s = istream_read_int16_le( inputStream );
63 st.t = istream_read_int16_le( inputStream );
72 void istream_read_md2Triangle( PointerInputStream& inputStream, md2Triangle_t& triangle ){
73 triangle.index_xyz[0] = istream_read_int16_le( inputStream );
74 triangle.index_xyz[1] = istream_read_int16_le( inputStream );
75 triangle.index_xyz[2] = istream_read_int16_le( inputStream );
76 triangle.index_st[0] = istream_read_int16_le( inputStream );
77 triangle.index_st[1] = istream_read_int16_le( inputStream );
78 triangle.index_st[2] = istream_read_int16_le( inputStream );
83 byte v[3]; // scaled byte to fit in frame mins/maxs
84 byte lightnormalindex;
87 void istream_read_md2XyzNormal( PointerInputStream& inputStream, md2XyzNormal_t& xyz ){
88 inputStream.read( xyz.v, 3 );
89 inputStream.read( &xyz.lightnormalindex, 1 );
92 #define MD2_XYZNORMAL_V0 0
93 #define MD2_XYZNORMAL_V1 1
94 #define MD2_XYZNORMAL_V2 2
95 #define MD2_XYZNORMAL_LNI 3
96 #define MD2_XYZNORMAL_SIZE 4
100 float scale[3]; // multiply byte verts by this
101 float translate[3]; // then add this
102 char name[16]; // frame name from grabbing
103 md2XyzNormal_t verts[1]; // variable sized
106 void istream_read_md2Frame( PointerInputStream& inputStream, md2Frame_t& frame ){
107 frame.scale[0] = istream_read_float32_le( inputStream );
108 frame.scale[1] = istream_read_float32_le( inputStream );
109 frame.scale[2] = istream_read_float32_le( inputStream );
110 frame.translate[0] = istream_read_float32_le( inputStream );
111 frame.translate[1] = istream_read_float32_le( inputStream );
112 frame.translate[2] = istream_read_float32_le( inputStream );
113 inputStream.read( reinterpret_cast<unsigned char*>( frame.name ), 16 );
118 // a positive integer starts a tristrip command, followed by that many
119 // vertex structures.
120 // a negative integer starts a trifan command, followed by -x vertexes
121 // a zero indicates the end of the command list.
122 // a vertex consists of a floating point s, a floating point t,
123 // and an integer vertex index.
128 unsigned char ident[4];
133 int framesize; // byte size of each frame
137 int num_st; // greater than num_xyz for seams
139 int num_glcmds; // dwords in strip/fan command list
142 int ofs_skins; // each skin is a MAX_SKINNAME string
143 int ofs_st; // byte offset from start for md2St_t
144 int ofs_tris; // offset for md2triangle_t
145 int ofs_frames; // offset for first md2Frame_t
147 int ofs_end; // end of file
151 void istream_read_md2Header( PointerInputStream& inputStream, md2Header_t& header ){
152 inputStream.read( header.ident, 4 );
153 header.version = istream_read_int32_le( inputStream );
154 header.skinwidth = istream_read_int32_le( inputStream );
155 header.skinheight = istream_read_int32_le( inputStream );
156 header.framesize = istream_read_int32_le( inputStream );
157 header.num_skins = istream_read_int32_le( inputStream );
158 header.num_xyz = istream_read_int32_le( inputStream );
159 header.num_st = istream_read_int32_le( inputStream );
160 header.num_tris = istream_read_int32_le( inputStream );
161 header.num_glcmds = istream_read_int32_le( inputStream );
162 header.num_frames = istream_read_int32_le( inputStream );
163 header.ofs_skins = istream_read_int32_le( inputStream );
164 header.ofs_st = istream_read_int32_le( inputStream );
165 header.ofs_tris = istream_read_int32_le( inputStream );
166 header.ofs_frames = istream_read_int32_le( inputStream );
167 header.ofs_glcmds = istream_read_int32_le( inputStream );
168 header.ofs_end = istream_read_int32_le( inputStream );
172 ArbitraryMeshVertex MD2Vertex_construct( const md2Header_t* pHeader, const md2Frame_t* pFrame, const md2XyzNormal_t* xyz, const md2St_t* st ){
173 return ArbitraryMeshVertex(
175 xyz->v[0] * pFrame->scale[0] + pFrame->translate[0],
176 xyz->v[1] * pFrame->scale[1] + pFrame->translate[1],
177 xyz->v[2] * pFrame->scale[2] + pFrame->translate[2]
180 g_mdl_normals[xyz->lightnormalindex][0],
181 g_mdl_normals[xyz->lightnormalindex][1],
182 g_mdl_normals[xyz->lightnormalindex][2]
185 (float)st->s / pHeader->skinwidth,
186 (float)st->t / pHeader->skinheight
191 void MD2Surface_read( Model& model, const byte* buffer, ArchiveFile& file ){
192 Surface& surface = model.newSurface();
195 PointerInputStream inputStream( buffer );
196 istream_read_md2Header( inputStream, header );
202 PointerInputStream frameStream( buffer + header.ofs_frames );
203 istream_read_md2Frame( frameStream, frame );
206 surface.indices().reserve( header.num_tris * 3 );
208 Array<md2XyzNormal_t> md2Xyz( header.num_xyz );
209 for ( Array<md2XyzNormal_t>::iterator i = md2Xyz.begin(); i != md2Xyz.end(); ++i )
211 istream_read_md2XyzNormal( frameStream, *i );
214 Array<md2St_t> md2St( header.num_st );
215 PointerInputStream stStream( buffer + header.ofs_st );
216 for ( Array<md2St_t>::iterator i = md2St.begin(); i != md2St.end(); ++i )
218 istream_read_md2St( stStream, *i );
221 UniqueVertexBuffer<ArbitraryMeshVertex> inserter( surface.vertices() );
222 inserter.reserve( header.num_st );
224 PointerInputStream triangleStream( buffer + header.ofs_tris );
225 for ( int i = 0; i < header.num_tris; ++i )
227 md2Triangle_t triangle;
228 istream_read_md2Triangle( triangleStream, triangle );
229 surface.indices().insert( inserter.insert( MD2Vertex_construct( &header, &frame, &md2Xyz[triangle.index_xyz[0]], &md2St[triangle.index_st[0]] ) ) );
230 surface.indices().insert( inserter.insert( MD2Vertex_construct( &header, &frame, &md2Xyz[triangle.index_xyz[1]], &md2St[triangle.index_st[1]] ) ) );
231 surface.indices().insert( inserter.insert( MD2Vertex_construct( &header, &frame, &md2Xyz[triangle.index_xyz[2]], &md2St[triangle.index_st[2]] ) ) );
235 char skinname[MD2_MAX_SKINNAME];
236 char skinnameRelative[MD2_MAX_SKINNAME];
237 char path[MD2_MAX_SKINNAME];
238 int i = MD2_MAX_SKINNAME;
239 PointerInputStream inputStream( buffer + header.ofs_skins );
240 inputStream.read( reinterpret_cast<byte*>( skinnameRelative ), MD2_MAX_SKINNAME );
241 // relative texture path - allows moving of models in game dir structure without changing the skinpath
242 // e.g. used in ufo:ai
243 if ( skinnameRelative[0] == '.' ) {
244 strncpy( path, file.getName(), MD2_MAX_SKINNAME );
248 if ( path[i] == '/' || path[i] == '\\' ) {
253 // globalErrorStream() << "modified skinname: " << path << " (path) and " << skinnameRelative << " (texture)" << "\n";
254 snprintf( skinname, MD2_MAX_SKINNAME, "%s%s", path, &skinnameRelative[1] );
255 // globalErrorStream() << skinname << "\n";
259 strcpy( skinname, skinnameRelative );
261 surface.setShader( skinname );
262 surface.updateAABB();
265 void MD2Model_read( Model& model, const byte* buffer, ArchiveFile& file ){
266 MD2Surface_read( model, buffer, file );
270 scene::Node& MD2Model_new( const byte* buffer, ArchiveFile& file ){
271 ModelNode* modelNode = new ModelNode();
272 MD2Model_read( modelNode->model(), buffer, file );
273 return modelNode->node();
276 scene::Node& MD2Model_default(){
277 ModelNode* modelNode = new ModelNode();
278 Model_constructNull( modelNode->model() );
279 return modelNode->node();
282 scene::Node& MD2Model_fromBuffer( unsigned char* buffer, ArchiveFile& file ){
283 if ( !ident_equal( buffer, MD2_IDENT ) ) {
284 globalErrorStream() << "MD2 read error: incorrect ident\n";
285 return MD2Model_default();
289 return MD2Model_new( buffer, file );
293 scene::Node& loadMD2Model( ArchiveFile& file ){
294 ScopedArchiveBuffer buffer( file );
295 return MD2Model_fromBuffer( buffer.buffer, file );