Merge remote-tracking branch 'ttimo/master'
[xonotic/netradiant.git] / plugins / md3model / mdl.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 "mdl.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 #include "mdlformat.h"
34
35 void istream_read_mdlHeader( PointerInputStream& inputStream, mdlHeader_t& header ){
36         inputStream.read( header.ident, 4 );
37         header.version = istream_read_int32_le( inputStream );
38         header.scale[0] = istream_read_float32_le( inputStream );
39         header.scale[1] = istream_read_float32_le( inputStream );
40         header.scale[2] = istream_read_float32_le( inputStream );
41         header.scale_origin[0] = istream_read_float32_le( inputStream );
42         header.scale_origin[1] = istream_read_float32_le( inputStream );
43         header.scale_origin[2] = istream_read_float32_le( inputStream );
44         header.boundingradius = istream_read_float32_le( inputStream );
45         header.eyeposition[0] = istream_read_float32_le( inputStream );
46         header.eyeposition[1] = istream_read_float32_le( inputStream );
47         header.eyeposition[2] = istream_read_float32_le( inputStream );
48         header.numskins = istream_read_int32_le( inputStream );
49         header.skinwidth = istream_read_int32_le( inputStream );
50         header.skinheight = istream_read_int32_le( inputStream );
51         header.numverts = istream_read_int32_le( inputStream );
52         header.numtris = istream_read_int32_le( inputStream );
53         header.numframes = istream_read_int32_le( inputStream );
54         header.synctype = istream_read_int32_le( inputStream );
55         header.flags = istream_read_int32_le( inputStream );
56         header.size = istream_read_float32_le( inputStream );
57 }
58
59 inline ArbitraryMeshVertex MDLVertex_construct( const mdlHeader_t& header, const mdlXyzNormal_t& xyz, const mdlSt_t& st, bool facesfront ){
60         return ArbitraryMeshVertex(
61                            Vertex3f(
62                                    xyz.v[0] * header.scale[0] + header.scale_origin[0],
63                                    xyz.v[1] * header.scale[1] + header.scale_origin[1],
64                                    xyz.v[2] * header.scale[2] + header.scale_origin[2]
65                                    ),
66                            Normal3f(
67                                    g_mdl_normals[xyz.lightnormalindex][0],
68                                    g_mdl_normals[xyz.lightnormalindex][1],
69                                    g_mdl_normals[xyz.lightnormalindex][2]
70                                    ),
71                            TexCoord2f(
72                                    ( (float)st.s / header.skinwidth ) + ( ( st.onseam == MDL_ONSEAM && !facesfront ) ? 0.5f : 0.0f ),
73                                    (float)st.t / header.skinheight
74                                    )
75                            );
76 }
77
78 class mdlVertex_t
79 {
80 public:
81 inline mdlVertex_t( int vertindex, int facesfront )
82         : m_vertindex( vertindex ), m_facesfront( facesfront )
83 {}
84 inline bool operator<( const mdlVertex_t& other ) const {
85         if ( m_facesfront < other.m_facesfront ) {
86                 return true;
87         }
88         if ( other.m_facesfront < m_facesfront ) {
89                 return false;
90         }
91
92         if ( m_vertindex < other.m_vertindex ) {
93                 return true;
94         }
95         if ( other.m_vertindex < m_vertindex ) {
96                 return false;
97         }
98
99         return false;
100 }
101 inline bool operator==( const mdlVertex_t& other ) const {
102         return m_vertindex == other.m_vertindex
103                    && m_facesfront == other.m_facesfront;
104 }
105
106 int m_vertindex;
107 int m_facesfront;
108 };
109
110 typedef const mdlTriangle_t* mdlTriangleIterator;
111
112 void MDLSurface_read( Surface& surface, const byte* buffer, const char* name ){
113         mdlHeader_t header;
114
115         PointerInputStream inputStream( buffer );
116         istream_read_mdlHeader( inputStream, header );
117
118         for ( int i = 0; i < header.numskins; ++i )
119         {
120                 switch ( istream_read_int32_le( inputStream ) )
121                 {
122                 case MDL_SKIN_SINGLE:
123                         inputStream.seek( header.skinwidth * header.skinheight );
124                         break;
125                 case MDL_SKIN_GROUP:
126                         int numskins = istream_read_int32_le( inputStream );
127                         inputStream.seek( numskins * ( 4 + ( header.skinwidth * header.skinheight ) ) );
128                         break;
129                 }
130         }
131
132         Array<mdlSt_t> mdlSts( header.numverts );
133         for ( Array<mdlSt_t>::iterator i = mdlSts.begin(); i != mdlSts.end(); ++i )
134         {
135                 ( *i ).onseam = istream_read_int32_le( inputStream );
136                 ( *i ).s = istream_read_int32_le( inputStream );
137                 ( *i ).t = istream_read_int32_le( inputStream );
138         }
139
140         Array<mdlTriangle_t> mdlTriangles( header.numtris );
141         for ( Array<mdlTriangle_t>::iterator i = mdlTriangles.begin(); i != mdlTriangles.end(); ++i )
142         {
143                 ( *i ).facesfront = istream_read_int32_le( inputStream );
144                 ( *i ).vertindex[0] = istream_read_int32_le( inputStream );
145                 ( *i ).vertindex[1] = istream_read_int32_le( inputStream );
146                 ( *i ).vertindex[2] = istream_read_int32_le( inputStream );
147         }
148
149         {
150                 bool found = false;
151                 for ( int i = 0; i < header.numframes && found == false; i++ )
152                 {
153                         switch ( istream_read_int32_le( inputStream ) )
154                         {
155                         case MDL_FRAME_SINGLE:
156                                 inputStream.seek( MDL_FRAME_SIZE );
157                                 found = true;
158                                 break;
159                         case MDL_FRAME_GROUP:
160                                 int numframes = istream_read_int32_le( inputStream );
161                                 inputStream.seek( ( MDL_XYZNORMAL_SIZE * 2 ) + ( numframes * 4 ) );
162                                 found = true;
163                                 break;
164                         }
165                 }
166         }
167
168         Array<mdlXyzNormal_t> mdlXyzNormals( header.numtris );
169         for ( Array<mdlXyzNormal_t>::iterator i = mdlXyzNormals.begin(); i != mdlXyzNormals.end(); ++i )
170         {
171                 inputStream.read( ( *i ).v, 3 );
172                 inputStream.read( &( *i ).lightnormalindex, 1 );
173         }
174
175         {
176                 VertexBuffer<mdlVertex_t> mdl_vertices;
177
178                 {
179                         UniqueVertexBuffer<mdlVertex_t> inserter( mdl_vertices );
180                         for ( Array<mdlTriangle_t>::iterator i = mdlTriangles.begin(); i != mdlTriangles.end(); ++i )
181                         {
182                                 surface.indices().insert( inserter.insert( mdlVertex_t( ( *i ).vertindex[0], ( *i ).facesfront ) ) );
183                                 surface.indices().insert( inserter.insert( mdlVertex_t( ( *i ).vertindex[1], ( *i ).facesfront ) ) );
184                                 surface.indices().insert( inserter.insert( mdlVertex_t( ( *i ).vertindex[2], ( *i ).facesfront ) ) );
185                         }
186                 }
187
188                 {
189                         surface.vertices().reserve( mdl_vertices.size() );
190
191                         for ( VertexBuffer<mdlVertex_t>::iterator i = mdl_vertices.begin(); i != mdl_vertices.end(); ++i )
192                         {
193                                 surface.vertices().push_back( MDLVertex_construct( header, mdlXyzNormals[( *i ).m_vertindex], mdlSts[( *i ).m_vertindex], ( *i ).m_facesfront == MDL_FACES_FRONT ) );
194                         }
195                 }
196         }
197
198         surface.setShader( name );
199         surface.updateAABB();
200 }
201
202 void MDLModel_read( Model& model, const byte* buffer, const char* name ){
203         MDLSurface_read( model.newSurface(), buffer, name );
204         model.updateAABB();
205 }
206
207 scene::Node& MDLModel_new( const byte* buffer, const char* name ){
208         ModelNode* modelNode = new ModelNode();
209         MDLModel_read( modelNode->model(), buffer, name );
210         return modelNode->node();
211 }
212
213 scene::Node& MDLModel_default(){
214         ModelNode* modelNode = new ModelNode();
215         Model_constructNull( modelNode->model() );
216         return modelNode->node();
217 }
218
219 scene::Node& MDLModel_fromBuffer( unsigned char* buffer, const char* name ){
220         if ( !ident_equal( buffer, MDL_IDENT ) ) {
221                 globalErrorStream() << "MDL read error: incorrect ident\n";
222                 return MDLModel_default();
223         }
224         else
225         {
226                 return MDLModel_new( buffer, name );
227         }
228 }
229
230 scene::Node& loadMDLModel( ArchiveFile& file ){
231         ScopedArchiveBuffer buffer( file );
232         return MDLModel_fromBuffer( buffer.buffer, file.getName() );
233 }