2da1ae9b6aed31e5b3a64791d518cb2f5709c667
[xonotic/netradiant.git] / tools / quake3 / q3data / p3dlib.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
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 "p3dlib.h"
23
24 #ifdef WIN32
25 #include <io.h>
26 #endif
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #define MAX_POLYSETS 64
32
33 #if defined ( __linux__ ) || defined ( __APPLE__ )
34 #define _strcmpi Q_stricmp
35 #define filelength Q_filelength
36 #define strlwr strlower
37 #endif
38 typedef struct
39 {
40         long len;
41
42         int numPairs;
43         char polysetNames[MAX_POLYSETS][256];
44         char shaders[MAX_POLYSETS][256];
45
46         char *buffer, *curpos;
47 } p3d_t;
48
49 static p3d_t p3d;
50
51 static int P3DProcess();
52 static int P3DGetToken( int restOfLine );
53
54 static char s_token[1024];
55 static int s_curpair;
56
57 /*
58 ** P3DLoad
59 **
60 */
61 int P3DLoad( const char *filename ){
62         FILE *fp = fopen( filename, "rb" );
63
64         if ( !fp ) {
65                 return 0;
66         }
67
68         memset( &p3d, 0, sizeof( p3d ) );
69
70         p3d.len = filelength( fileno( fp ) );
71
72         p3d.curpos = p3d.buffer = malloc( p3d.len );
73
74         if ( fread( p3d.buffer, p3d.len, 1, fp ) != 1 ) {
75                 fclose( fp );
76                 return 0;
77         }
78
79         fclose( fp );
80
81         return P3DProcess();
82 }
83
84 /*
85 ** P3DClose
86 **
87 */
88 void P3DClose(){
89         if ( p3d.buffer ) {
90                 free( p3d.buffer );
91                 p3d.buffer = 0;
92         }
93 }
94
95 int CharIsTokenDelimiter( int ch ){
96         if ( ch <= 32 ) {
97                 return 1;
98         }
99         return 0;
100 }
101
102 int P3DSkipToToken( const char *name ){
103         while ( P3DGetToken( 0 ) )
104         {
105                 if ( !_strcmpi( s_token, name ) ) {
106                         return 1;
107                 }
108         }
109
110         return 0;
111 }
112
113 /*
114 ** P3DGetToken
115 **
116 */
117 int P3DGetToken( int restOfLine ){
118         int i = 0;
119
120         if ( p3d.buffer == 0 ) {
121                 return 0;
122         }
123
124         if ( ( p3d.curpos - p3d.buffer ) == p3d.len ) {
125                 return 0;
126         }
127
128         // skip over crap
129         while ( ( ( p3d.curpos - p3d.buffer ) < p3d.len ) &&
130                         ( *p3d.curpos <= 32 ) )
131         {
132                 p3d.curpos++;
133         }
134
135         while ( ( p3d.curpos - p3d.buffer ) < p3d.len )
136         {
137                 s_token[i] = *p3d.curpos;
138
139                 p3d.curpos++;
140                 i++;
141
142                 if ( ( CharIsTokenDelimiter( s_token[i - 1] ) && !restOfLine ) ||
143                          ( ( s_token[i - 1] == '\n' ) ) ) {
144                         s_token[i - 1] = 0;
145                         break;
146                 }
147         }
148
149         s_token[i] = 0;
150
151         return 1;
152 }
153
154 int P3DGetNextPair( char **psetName, char **associatedShader ){
155         if ( s_curpair < p3d.numPairs ) {
156                 *psetName = p3d.polysetNames[s_curpair];
157                 *associatedShader = p3d.shaders[s_curpair];
158                 s_curpair++;
159                 return 1;
160         }
161
162         return 0;
163 }
164
165 int P3DSkipToTokenInBlock( const char *name ){
166         int iLevel = 0;
167
168         while ( P3DGetToken( 0 ) )
169         {
170                 if ( !_strcmpi( s_token, "}" ) ) {
171                         iLevel--;
172                 }
173                 else if ( !_strcmpi( s_token, "{" ) ) {
174                         iLevel++;
175                 }
176
177                 if ( !_strcmpi( s_token, name ) ) {
178                         return 1;
179                 }
180
181                 if ( iLevel == 0 ) {
182                         return 0;
183                 }
184         }
185
186         return 0;
187 }
188
189 /*
190 ** P3DProcess
191 **
192 ** Nothing fancy here.
193 */
194 int P3DProcess(){
195
196         s_curpair = 0;
197
198         // first token should be a string
199         P3DGetToken( 1 );       // Voodoo Ascii File
200
201         // skip to the first Obj declaration
202         while ( P3DGetToken( 0 ) )
203         {
204                 if ( !_strcmpi( s_token, "Obj" ) ) {
205                         int j = 0, k = 0;
206
207                         if ( P3DSkipToToken( "Text" ) ) {
208                                 if ( P3DSkipToTokenInBlock( "TMap" ) ) {
209                                         char *p;
210
211                                         if ( !P3DSkipToToken( "Path" ) ) {
212                                                 return 0;
213                                         }
214
215                                         if ( !P3DGetToken( 1 ) ) {
216                                                 return 0;
217                                         }
218
219                                         while ( s_token[j] != 0 )
220                                         {
221                                                 if ( s_token[j] == '\\' ) {
222                                                         j++;
223                                                         p3d.shaders[p3d.numPairs][k] = '/';
224                                                 }
225                                                 else
226                                                 {
227                                                         p3d.shaders[p3d.numPairs][k] = s_token[j];
228                                                 }
229                                                 j++;
230                                                 k++;
231                                         }
232                                         p3d.shaders[p3d.numPairs][k] = 0;
233
234                                         //
235                                         // strip off any explicit extensions
236                                         //
237                                         if ( ( p = strrchr( p3d.shaders[p3d.numPairs], '/' ) ) != 0 ) {
238                                                 while ( *p )
239                                                 {
240                                                         if ( *p == '.' ) {
241                                                                 *p = 0;
242                                                                 break;
243                                                         }
244                                                         p++;
245                                                 }
246                                         }
247
248                                         //
249                                         // skip to the end of the Object and grab its name
250                                         //
251                                         if ( !P3DSkipToToken( "Name" ) ) {
252                                                 return 0;
253                                         }
254
255                                         if ( P3DGetToken( 0 ) ) {
256                                                 // strip off leading 'Obj_' if it exists
257                                                 if ( strstr( s_token, "Obj_" ) == s_token ) {
258                                                         strcpy( p3d.polysetNames[p3d.numPairs], s_token + strlen( "Obj_" ) );
259                                                 }
260                                                 else{
261                                                         strcpy( p3d.polysetNames[p3d.numPairs], s_token );
262                                                 }
263
264                                                 // strip off trailing unused color information
265 //                                              if ( strrchr( p3d.polysetNames[p3d.numPairs], '_' ) != 0 )
266 //                                                      *strrchr( p3d.polysetNames[p3d.numPairs], '_' ) = 0;
267
268                                                 p3d.numPairs++;
269                                         }
270                                         else
271                                         {
272                                                 return 0;
273                                         }
274                                 }
275                         }
276                 }
277         }
278
279         s_curpair = 0;
280
281         return 1;
282 }
283
284 #if 0
285 void SkinFromP3D( const char *file ){
286         char filename[1024];
287         char *psetName, *associatedShader;
288
289         /*
290         ** a P3D file contains a list of polysets, each with a list of associated
291         ** texture names that constitute it's
292         **
293         ** Thus:
294         **
295         ** P3D file -> skin
296         ** polyset  -> polyset
297         **   texture -> texture.SHADER becomes polyset's shader
298         */
299         sprintf( filename, "%s/%s", g_cddir, file );
300
301         if ( !P3DLoad( filename ) ) {
302                 Error( "unable to load '%s'", filename );
303         }
304
305         while ( P3DGetNextPair( &psetName, &associatedShader ) )
306         {
307                 int i;
308
309                 // find the polyset in the object that this particular pset/shader pair
310                 // corresponds to and append the shader to it
311                 for ( i = 0; i < g_data.model.numSurfaces; i++ )
312                 {
313                         if ( !_strcmpi( g_data.surfData[i].header.name, psetName ) ) {
314                                 char *p;
315
316                                 if ( strstr( associatedShader, gamedir + 1 ) ) {
317                                         p = strstr( associatedShader, gamedir + 1 ) + strlen( gamedir ) - 1;
318                                 }
319                                 else
320                                 {
321                                         p = associatedShader;
322                                 }
323
324                                 strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, p );
325
326                                 g_data.surfData[i].header.numShaders++;
327                         }
328                 }
329
330         }
331
332         P3DClose();
333 }
334 #endif