]> icculus.org git repositories - divverent/netradiant.git/blob - plugins/md3model/md2.cpp
option -randomsamples: makes -samples use adaptive random subsampling (only subsample...
[divverent/netradiant.git] / plugins / md3model / md2.cpp
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
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.
11
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.
16
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
20 */
21
22 #include "md2.h"
23
24 #include "ifilesystem.h"
25 #include "imodel.h"
26
27 #include "imagelib.h"
28 #include "bytestreamutils.h"
29
30 #include "model.h"
31 #include "ident.h"
32 #include "mdlnormals.h"
33
34 typedef unsigned char byte;
35
36 /*
37 ========================================================================
38
39 .MD2 triangle model file format
40
41 ========================================================================
42 */
43 #define MD2_NUMVERTEXNORMALS 162
44 #define MD2_MAX_SKINNAME        64
45
46 const unsigned char MD2_IDENT[4] = { 'I', 'D', 'P', '2', };
47 #define MD2_VERSION     8
48
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
54
55 typedef struct
56 {
57         short   s;
58         short   t;
59 } md2St_t;
60
61 void istream_read_md2St(PointerInputStream& inputStream, md2St_t& st)
62 {
63   st.s = istream_read_int16_le(inputStream);
64   st.t = istream_read_int16_le(inputStream);
65 }
66
67 typedef struct 
68 {
69         short   index_xyz[3];
70         short   index_st[3];
71 } md2Triangle_t;
72
73 void istream_read_md2Triangle(PointerInputStream& inputStream, md2Triangle_t& triangle)
74 {
75   triangle.index_xyz[0] = istream_read_int16_le(inputStream);
76   triangle.index_xyz[1] = istream_read_int16_le(inputStream);
77   triangle.index_xyz[2] = istream_read_int16_le(inputStream);
78   triangle.index_st[0] = istream_read_int16_le(inputStream);
79   triangle.index_st[1] = istream_read_int16_le(inputStream);
80   triangle.index_st[2] = istream_read_int16_le(inputStream);
81 }
82
83 typedef struct
84 {
85         byte    v[3];                   // scaled byte to fit in frame mins/maxs
86         byte    lightnormalindex;
87 } md2XyzNormal_t;
88
89 void istream_read_md2XyzNormal(PointerInputStream& inputStream, md2XyzNormal_t& xyz)
90 {
91   inputStream.read(xyz.v, 3);
92   inputStream.read(&xyz.lightnormalindex, 1);
93 }
94
95 #define MD2_XYZNORMAL_V0   0
96 #define MD2_XYZNORMAL_V1   1
97 #define MD2_XYZNORMAL_V2   2
98 #define MD2_XYZNORMAL_LNI  3
99 #define MD2_XYZNORMAL_SIZE 4
100
101 typedef struct
102 {
103         float           scale[3];       // multiply byte verts by this
104         float           translate[3];   // then add this
105         char            name[16];       // frame name from grabbing
106         md2XyzNormal_t  verts[1];       // variable sized
107 } md2Frame_t;
108
109 void istream_read_md2Frame(PointerInputStream& inputStream, md2Frame_t& frame)
110 {
111   frame.scale[0] = istream_read_float32_le(inputStream);
112   frame.scale[1] = istream_read_float32_le(inputStream);
113   frame.scale[2] = istream_read_float32_le(inputStream);
114   frame.translate[0] = istream_read_float32_le(inputStream);
115   frame.translate[1] = istream_read_float32_le(inputStream);
116   frame.translate[2] = istream_read_float32_le(inputStream);
117   inputStream.read(reinterpret_cast<unsigned char*>(frame.name), 16);
118 }
119
120
121 // the glcmd format:
122 // a positive integer starts a tristrip command, followed by that many
123 // vertex structures.
124 // a negative integer starts a trifan command, followed by -x vertexes
125 // a zero indicates the end of the command list.
126 // a vertex consists of a floating point s, a floating point t,
127 // and an integer vertex index.
128
129
130 typedef struct
131 {
132         unsigned char ident[4];
133         int                     version;
134
135         int                     skinwidth;
136         int                     skinheight;
137         int                     framesize;              // byte size of each frame
138
139         int                     num_skins;
140         int                     num_xyz;
141         int                     num_st;                 // greater than num_xyz for seams
142         int                     num_tris;
143         int                     num_glcmds;             // dwords in strip/fan command list
144         int                     num_frames;
145
146         int                     ofs_skins;              // each skin is a MAX_SKINNAME string
147         int                     ofs_st;                 // byte offset from start for md2St_t
148         int                     ofs_tris;               // offset for md2triangle_t
149         int                     ofs_frames;             // offset for first md2Frame_t
150         int                     ofs_glcmds;     
151         int                     ofs_end;                // end of file
152
153 } md2Header_t;
154
155 void istream_read_md2Header(PointerInputStream& inputStream, md2Header_t& header)
156 {
157   inputStream.read(header.ident, 4);
158   header.version = istream_read_int32_le(inputStream);
159   header.skinwidth = istream_read_int32_le(inputStream);
160   header.skinheight = istream_read_int32_le(inputStream);
161   header.framesize = istream_read_int32_le(inputStream);
162   header.num_skins = istream_read_int32_le(inputStream);
163   header.num_xyz = istream_read_int32_le(inputStream);
164   header.num_st = istream_read_int32_le(inputStream);
165   header.num_tris = istream_read_int32_le(inputStream);
166   header.num_glcmds = istream_read_int32_le(inputStream);
167   header.num_frames = istream_read_int32_le(inputStream);
168   header.ofs_skins = istream_read_int32_le(inputStream);
169   header.ofs_st = istream_read_int32_le(inputStream);
170   header.ofs_tris = istream_read_int32_le(inputStream);
171   header.ofs_frames = istream_read_int32_le(inputStream);
172   header.ofs_glcmds = istream_read_int32_le(inputStream);
173   header.ofs_end = istream_read_int32_le(inputStream);
174 }
175
176
177 ArbitraryMeshVertex MD2Vertex_construct(const md2Header_t* pHeader, const md2Frame_t* pFrame, const md2XyzNormal_t* xyz, const md2St_t* st)
178 {
179   return ArbitraryMeshVertex(
180     Vertex3f(
181       xyz->v[0] * pFrame->scale[0] + pFrame->translate[0],
182       xyz->v[1] * pFrame->scale[1] + pFrame->translate[1],
183       xyz->v[2] * pFrame->scale[2] + pFrame->translate[2]
184     ),
185     Normal3f(
186       g_mdl_normals[xyz->lightnormalindex][0],
187       g_mdl_normals[xyz->lightnormalindex][1],
188       g_mdl_normals[xyz->lightnormalindex][2]
189     ),
190     TexCoord2f(
191       (float)st->s / pHeader->skinwidth,
192       (float)st->t / pHeader->skinheight
193     )
194   );
195 }
196
197 void MD2Surface_read(Model& model, const byte* buffer, ArchiveFile& file)
198 {
199   Surface& surface = model.newSurface();
200   md2Header_t header;
201   {
202     PointerInputStream inputStream(buffer);
203     istream_read_md2Header(inputStream, header);
204   }
205
206   {
207
208     md2Frame_t frame;
209     PointerInputStream frameStream(buffer + header.ofs_frames);
210     istream_read_md2Frame(frameStream, frame);
211
212
213     surface.indices().reserve(header.num_tris * 3);
214
215     Array<md2XyzNormal_t> md2Xyz(header.num_xyz);
216     for(Array<md2XyzNormal_t>::iterator i = md2Xyz.begin(); i != md2Xyz.end(); ++i)
217     {
218       istream_read_md2XyzNormal(frameStream, *i);
219     }
220
221     Array<md2St_t> md2St(header.num_st);
222     PointerInputStream stStream(buffer + header.ofs_st);
223     for(Array<md2St_t>::iterator i = md2St.begin(); i != md2St.end(); ++i)
224     {
225       istream_read_md2St(stStream, *i);
226     }
227
228     UniqueVertexBuffer<ArbitraryMeshVertex> inserter(surface.vertices());
229     inserter.reserve(header.num_st);
230
231     PointerInputStream triangleStream(buffer + header.ofs_tris);
232           for(int i = 0; i < header.num_tris; ++i)
233     {
234       md2Triangle_t triangle;
235       istream_read_md2Triangle(triangleStream, triangle);
236       surface.indices().insert(inserter.insert(MD2Vertex_construct(&header, &frame, &md2Xyz[triangle.index_xyz[0]], &md2St[triangle.index_st[0]])));
237       surface.indices().insert(inserter.insert(MD2Vertex_construct(&header, &frame, &md2Xyz[triangle.index_xyz[1]], &md2St[triangle.index_st[1]])));
238       surface.indices().insert(inserter.insert(MD2Vertex_construct(&header, &frame, &md2Xyz[triangle.index_xyz[2]], &md2St[triangle.index_st[2]])));
239     }
240   }
241
242   char skinname[MD2_MAX_SKINNAME];
243   char skinnameRelative[MD2_MAX_SKINNAME];
244   char path[MD2_MAX_SKINNAME];
245   int i = MD2_MAX_SKINNAME;
246   PointerInputStream inputStream(buffer + header.ofs_skins);
247   inputStream.read(reinterpret_cast<byte*>(skinnameRelative), MD2_MAX_SKINNAME);
248   // relative texture path - allows moving of models in game dir structure without changing the skinpath
249   // e.g. used in ufo:ai
250   if (skinnameRelative[0] == '.') 
251   {
252         strncpy(path, file.getName(), MD2_MAX_SKINNAME);
253         for (; i--;) 
254         {
255             // skip filename
256             if (path[i] == '/' || path[i] == '\\')
257                 break;
258             path[i] = '\0';
259         }
260 //      globalErrorStream() << "modified skinname: " << path << " (path) and " << skinnameRelative << " (texture)" << "\n";
261         snprintf(skinname, MD2_MAX_SKINNAME, "%s%s", path, &skinnameRelative[1]);
262 //      globalErrorStream() << skinname << "\n";
263   } 
264   else
265   {
266         strcpy(skinname, skinnameRelative);
267   }
268   surface.setShader(skinname);
269   surface.updateAABB();
270 }
271
272 void MD2Model_read(Model& model, const byte* buffer, ArchiveFile& file)
273 {
274   MD2Surface_read(model, buffer, file);
275   model.updateAABB();
276 }
277
278 scene::Node& MD2Model_new(const byte* buffer, ArchiveFile& file)
279 {
280   ModelNode* modelNode = new ModelNode();
281   MD2Model_read(modelNode->model(), buffer, file);
282   return modelNode->node();
283 }
284
285 scene::Node& MD2Model_default()
286 {
287   ModelNode* modelNode = new ModelNode();
288   Model_constructNull(modelNode->model());
289   return modelNode->node();
290 }
291
292 scene::Node& MD2Model_fromBuffer(unsigned char* buffer, ArchiveFile& file)
293 {
294   if (!ident_equal(buffer, MD2_IDENT))
295   {
296           globalErrorStream() << "MD2 read error: incorrect ident\n";
297     return MD2Model_default();
298   }
299   else
300   {
301     return MD2Model_new(buffer, file);
302   }
303 }
304
305 scene::Node& loadMD2Model(ArchiveFile& file)
306 {
307   ScopedArchiveBuffer buffer(file);
308   return MD2Model_fromBuffer(buffer.buffer, file);
309 }