1 //********************************************************************************************
2 //*
3 //* This file is part of Egoboo.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 /// @file file_formats/mpd_file.c
21 /// @brief Functions for raw read and write access to the .mpd file type
22 /// @details
23
24 #include "mpd_file.h"
25 #include "log.h"
26
27 #include "egoboo_math.inl"
28 #include "egoboo_endian.h"
29 #include "egoboo_fileutil.h"
30 #include "egoboo_strutil.h"
31 #include "egoboo.h"
32
33 //--------------------------------------------------------------------------------------------
34 //--------------------------------------------------------------------------------------------
35
36 static mpd_info_t * mpd_info_ctor( mpd_info_t * pinfo );
37 static mpd_info_t * mpd_info_dtor( mpd_info_t * pinfo );
38
39 static mpd_mem_t * mpd_mem_ctor( mpd_mem_t * pmem );
40 static mpd_mem_t * mpd_mem_dtor( mpd_mem_t * pmem );
41 static bool_t mpd_mem_free( mpd_mem_t * pmem );
42 static bool_t mpd_mem_alloc( mpd_mem_t * pmem, mpd_info_t * pinfo );
43
44 //--------------------------------------------------------------------------------------------
45 //--------------------------------------------------------------------------------------------
46
47 fvec3_t map_twist_nrm[256];
48 Uint32 map_twist_y[256]; // For surface normal of mesh
49 Uint32 map_twist_x[256];
50 float map_twistvel_x[256]; // For sliding down steep hills
51 float map_twistvel_y[256];
52 float map_twistvel_z[256];
53 Uint8 map_twist_flat[256];
54
55 tile_definition_t tile_dict[MAXMESHTYPE];
56
57 //--------------------------------------------------------------------------------------------
58 //--------------------------------------------------------------------------------------------
tile_dictionary_load_vfs(const char * filename,tile_definition_t dict[],size_t dict_size)59 void tile_dictionary_load_vfs( const char * filename, tile_definition_t dict[], size_t dict_size )
60 {
61 /// @details ZZ@> This function loads fan types for the terrain
62
63 Uint32 cnt, entry, vertices, commandsize;
64 int numfantype, fantype, bigfantype;
65 int numcommand, command;
66 int itmp;
67 float ftmp;
68 vfs_FILE* fileread;
69
70 if ( !VALID_CSTR( filename ) || NULL == dict || dict_size < 2 ) return;
71
72 // Initialize all mesh types to 0
73 for ( entry = 0; entry < dict_size; entry++ )
74 {
75 dict[entry].numvertices = 0;
76 dict[entry].command_count = 0;
77 }
78
79 // Open the file and go to it
80 fileread = vfs_openRead( filename );
81 if ( NULL == fileread )
82 {
83 log_error( "Cannot load the tile definitions \"%s\".\n", filename );
84 return;
85 }
86
87 numfantype = fget_next_int( fileread );
88
89 for ( fantype = 0; fantype < numfantype; fantype++ )
90 {
91 bigfantype = fantype + dict_size / 2; // Duplicate for 64x64 tiles
92
93 vertices = fget_next_int( fileread );
94 dict[fantype].numvertices = vertices;
95 dict[bigfantype].numvertices = vertices; // Dupe
96
97 for ( cnt = 0; cnt < vertices; cnt++ )
98 {
99 itmp = fget_next_int( fileread );
100
101 ftmp = fget_next_float( fileread );
102 dict[fantype].u[cnt] = ftmp;
103 dict[bigfantype].u[cnt] = ftmp; // Dupe
104
105 ftmp = fget_next_float( fileread );
106 dict[fantype].v[cnt] = ftmp;
107 dict[bigfantype].v[cnt] = ftmp; // Dupe
108 }
109
110 numcommand = fget_next_int( fileread );
111 dict[fantype].command_count = numcommand;
112 dict[bigfantype].command_count = numcommand; // Dupe
113
114 for ( entry = 0, command = 0; command < numcommand; command++ )
115 {
116 commandsize = fget_next_int( fileread );
117 dict[fantype].command_entries[command] = commandsize;
118 dict[bigfantype].command_entries[command] = commandsize; // Dupe
119
120 for ( cnt = 0; cnt < commandsize; cnt++ )
121 {
122 itmp = fget_next_int( fileread );
123 dict[fantype].command_verts[entry] = itmp;
124 dict[bigfantype].command_verts[entry] = itmp; // Dupe
125
126 entry++;
127 }
128 }
129 }
130
131 vfs_close( fileread );
132
133 // Correct all of them silly texture positions for seamless tiling
134 for ( entry = 0; entry < dict_size / 2; entry++ )
135 {
136 for ( cnt = 0; cnt < dict[entry].numvertices; cnt++ )
137 {
138 dict[entry].u[cnt] = (( 0.6f / 32 ) + ( dict[entry].u[cnt] * 30.8f / 32 ) ) / 8;
139 dict[entry].v[cnt] = (( 0.6f / 32 ) + ( dict[entry].v[cnt] * 30.8f / 32 ) ) / 8;
140 }
141 }
142
143 // Do for big tiles too
144 for ( /* nothing */; entry < dict_size; entry++ )
145 {
146 for ( cnt = 0; cnt < dict[entry].numvertices; cnt++ )
147 {
148 dict[entry].u[cnt] = (( 0.6f / 64 ) + ( dict[entry].u[cnt] * 62.8f / 64 ) ) / 4;
149 dict[entry].v[cnt] = (( 0.6f / 64 ) + ( dict[entry].v[cnt] * 62.8f / 64 ) ) / 4;
150 }
151 }
152 }
153
154 //--------------------------------------------------------------------------------------------
155 //--------------------------------------------------------------------------------------------
mpd_ctor(mpd_t * pmesh)156 mpd_t * mpd_ctor( mpd_t * pmesh )
157 {
158 if ( NULL == pmesh ) return NULL;
159
160 memset( pmesh, 0, sizeof( *pmesh ) );
161
162 if ( NULL == mpd_mem_ctor( &( pmesh->mem ) ) ) return NULL;
163 if ( NULL == mpd_info_ctor( &( pmesh->info ) ) ) return NULL;
164
165 return pmesh;
166 }
167
168 //--------------------------------------------------------------------------------------------
mpd_dtor(mpd_t * pmesh)169 mpd_t * mpd_dtor( mpd_t * pmesh )
170 {
171 if ( NULL == pmesh ) return NULL;
172
173 if ( NULL == mpd_mem_dtor( &( pmesh->mem ) ) ) return NULL;
174 if ( NULL == mpd_info_dtor( &( pmesh->info ) ) ) return NULL;
175
176 return pmesh;
177 }
178
179 //--------------------------------------------------------------------------------------------
mpd_free(mpd_t * pmesh)180 bool_t mpd_free( mpd_t * pmesh )
181 {
182 if ( NULL == pmesh ) return bfalse;
183
184 mpd_mem_free( &( pmesh->mem ) );
185
186 return btrue;
187 }
188
189 //--------------------------------------------------------------------------------------------
mpd_load(const char * loadname,mpd_t * pmesh)190 mpd_t * mpd_load( const char *loadname, mpd_t * pmesh )
191 {
192 ///// @details ZZ@> This function loads the level.mpd file
193 FILE* fileread;
194 int itmp;
195 float ftmp;
196 Uint32 fan, cnt;
197 Uint32 tiles_count;
198 Uint8 btemp;
199
200 mpd_info_t * pinfo;
201 mpd_mem_t * pmem;
202
203 if ( NULL == pmesh || INVALID_CSTR( loadname ) ) return pmesh;
204
205 printf( "---- mpd_load(\"%s\",%p)\n", loadname, pmesh );
206
207 pinfo = &( pmesh->info );
208 pmem = &( pmesh->mem );
209
210 fileread = fopen( loadname, "rb" );
211 if ( NULL == fileread )
212 {
213 log_warning( "mpd_load() - cannot find \"%s\"!!\n", loadname );
214 return NULL;
215 }
216
217 fread( &itmp, 4, 1, fileread );
218 if ( MAPID != ( Uint32 )ENDIAN_INT32( itmp ) )
219 {
220 log_warning( "mpd_load() - this is not a valid level.mpd!!\n" );
221 fclose( fileread );
222 return NULL;
223 }
224
225 // Read the number of vertices
226 fread( &itmp, 4, 1, fileread ); pinfo->vertcount = ( int )ENDIAN_INT32( itmp );
227
228 // grab the tiles in x and y
229 fread( &itmp, 4, 1, fileread ); pinfo->tiles_x = ( int )ENDIAN_INT32( itmp );
230 if ( pinfo->tiles_x >= MAXMESHTILEY )
231 {
232 mpd_dtor( pmesh );
233 log_warning( "mpd_load() - invalid mpd size. Mesh too large in x direction.\n" );
234 fclose( fileread );
235 return NULL;
236 }
237
238 fread( &itmp, 4, 1, fileread ); pinfo->tiles_y = ( int )ENDIAN_INT32( itmp );
239 if ( pinfo->tiles_y >= MAXMESHTILEY )
240 {
241 mpd_dtor( pmesh );
242 log_warning( "mpd_load() - invalid mpd size. Mesh too large in y direction.\n" );
243 fclose( fileread );
244 return NULL;
245 }
246
247 // allocate the mesh memory
248 if ( !mpd_mem_alloc( pmem, pinfo ) )
249 {
250 mpd_dtor( pmesh );
251 fclose( fileread );
252 log_warning( "mpd_load() - could not allocate memory for the mesh!!\n" );
253 return NULL;
254 }
255
256 tiles_count = pinfo->tiles_x * pinfo->tiles_y;
257
258 // Load fan data
259 for ( fan = 0; fan < tiles_count; fan++ )
260 {
261 fread( &itmp, 4, 1, fileread );
262 pmem->tile_list[fan].type = CLIP_TO_08BITS( ENDIAN_INT32( itmp ) >> 24 );
263 pmem->tile_list[fan].fx = CLIP_TO_08BITS( ENDIAN_INT32( itmp ) >> 16 );
264 pmem->tile_list[fan].img = CLIP_TO_16BITS( ENDIAN_INT32( itmp ) >> 0 );
265 }
266
267 // Load twist data
268 for ( fan = 0; fan < tiles_count; fan++ )
269 {
270 fread( &itmp, 1, 1, fileread );
271 pmem->tile_list[fan].twist = ENDIAN_INT32( itmp );
272 }
273
274 // Load vertex x data
275 for ( cnt = 0; cnt < pmem->vcount; cnt++ )
276 {
277 fread( &ftmp, 4, 1, fileread );
278 pmem->vlst[cnt].pos.x = ENDIAN_FLOAT( ftmp );
279 }
280
281 // Load vertex y data
282 for ( cnt = 0; cnt < pmem->vcount; cnt++ )
283 {
284 fread( &ftmp, 4, 1, fileread );
285 pmem->vlst[cnt].pos.y = ENDIAN_FLOAT( ftmp );
286 }
287
288 // Load vertex z data
289 for ( cnt = 0; cnt < pmem->vcount; cnt++ )
290 {
291 fread( &ftmp, 4, 1, fileread );
292 pmem->vlst[cnt].pos.z = ENDIAN_FLOAT( ftmp ) / 16.0f; // Cartman uses 4 bit fixed point for Z
293 }
294
295 // Load vertex a data
296 for ( cnt = 0; cnt < pmem->vcount; cnt++ )
297 {
298 fread( &btemp, 1, 1, fileread );
299 pmem->vlst[cnt].a = 0; // btemp;
300 }
301
302 fclose( fileread );
303
304 return pmesh;
305 }
306
307 //--------------------------------------------------------------------------------------------
308 //--------------------------------------------------------------------------------------------
mpd_info_ctor(mpd_info_t * pinfo)309 mpd_info_t * mpd_info_ctor( mpd_info_t * pinfo )
310 {
311 if ( NULL == pinfo ) return pinfo;
312
313 memset( pinfo, 0, sizeof( *pinfo ) );
314
315 return pinfo;
316 }
317
318 //--------------------------------------------------------------------------------------------
mpd_info_dtor(mpd_info_t * pinfo)319 mpd_info_t * mpd_info_dtor( mpd_info_t * pinfo )
320 {
321 if ( NULL == pinfo ) return NULL;
322
323 memset( pinfo, 0, sizeof( *pinfo ) );
324
325 return pinfo;
326 }
327
328 //--------------------------------------------------------------------------------------------
329 //--------------------------------------------------------------------------------------------
mpd_mem_ctor(mpd_mem_t * pmem)330 mpd_mem_t * mpd_mem_ctor( mpd_mem_t * pmem )
331 {
332 if ( NULL == pmem ) return pmem;
333
334 memset( pmem, 0, sizeof( *pmem ) );
335
336 return pmem;
337 }
338
339 //--------------------------------------------------------------------------------------------
mpd_mem_dtor(mpd_mem_t * pmem)340 mpd_mem_t * mpd_mem_dtor( mpd_mem_t * pmem )
341 {
342 if ( NULL == pmem ) return NULL;
343
344 mpd_mem_free( pmem );
345 memset( pmem, 0, sizeof( *pmem ) );
346
347 return pmem;
348 }
349
350 //--------------------------------------------------------------------------------------------
mpd_mem_alloc(mpd_mem_t * pmem,mpd_info_t * pinfo)351 bool_t mpd_mem_alloc( mpd_mem_t * pmem, mpd_info_t * pinfo )
352 {
353 int tile_count;
354
355 if ( NULL == pmem || NULL == pinfo || 0 == pinfo->vertcount ) return bfalse;
356
357 // free any memory already allocated
358 if ( !mpd_mem_free( pmem ) ) return bfalse;
359
360 if ( pinfo->vertcount > MESH_MAXTOTALVERTRICES )
361 {
362 log_warning( "mpd_mem_alloc() - mesh requires too much memory ( %d requested, but max is %d ). \n", pinfo->vertcount, MESH_MAXTOTALVERTRICES );
363 return bfalse;
364 }
365
366 // allocate new memory
367 pmem->vlst = EGOBOO_NEW_ARY( mpd_vertex_t, pinfo->vertcount );
368 if ( NULL == pmem->vlst )
369 {
370 mpd_mem_free( pmem );
371 log_error( "mpd_mem_alloc() - reduce the maximum number of vertices! (Check MESH_MAXTOTALVERTRICES)\n" );
372 return bfalse;
373 }
374 pmem->vcount = pinfo->vertcount;
375
376 tile_count = pinfo->tiles_x * pinfo->tiles_y;
377 pmem->tile_list = EGOBOO_NEW_ARY( tile_info_t, tile_count );
378 if ( NULL == pmem->tile_list )
379 {
380 mpd_mem_free( pmem );
381 log_error( "mpd_mem_alloc() - not enough memory to allocate the tile info\n" );
382 return bfalse;
383 }
384 pmem->tile_count = tile_count;
385
386 return btrue;
387 }
388
389 //--------------------------------------------------------------------------------------------
mpd_mem_free(mpd_mem_t * pmem)390 bool_t mpd_mem_free( mpd_mem_t * pmem )
391 {
392 if ( NULL == pmem ) return bfalse;
393
394 // free the memory
395 EGOBOO_DELETE_ARY( pmem->vlst );
396 pmem->vcount = 0;
397
398 EGOBOO_DELETE_ARY( pmem->tile_list );
399 pmem->tile_count = 0;
400
401 return btrue;
402 }
403
404 //--------------------------------------------------------------------------------------------
405 //--------------------------------------------------------------------------------------------
cartman_get_twist(int x,int y)406 Uint8 cartman_get_twist( int x, int y )
407 {
408 Uint8 twist;
409
410 // x and y should be from -7 to 8
411 if ( x < -7 ) x = -7;
412 if ( x > 8 ) x = 8;
413 if ( y < -7 ) y = -7;
414 if ( y > 8 ) y = 8;
415
416 // Now between 0 and 15
417 x = x + 7;
418 y = y + 7;
419 twist = ( y << 4 ) + x;
420
421 return twist;
422 }
423
424 //--------------------------------------------------------------------------------------------
twist_to_normal(Uint8 twist,float v[],float slide)425 bool_t twist_to_normal( Uint8 twist, float v[], float slide )
426 {
427 int ix, iy;
428 float dx, dy;
429 float nx, ny, nz, nz2;
430 float diff_xy;
431
432 if ( NULL == v ) return bfalse;
433
434 diff_xy = 128.0f / slide;
435
436 ix = ( twist >> 0 ) & 0x0f;
437 iy = ( twist >> 4 ) & 0x0f;
438 ix -= 7;
439 iy -= 7;
440
441 dx = -ix / ( float )CARTMAN_FIXNUM * ( float )CARTMAN_SLOPE;
442 dy = iy / ( float )CARTMAN_FIXNUM * ( float )CARTMAN_SLOPE;
443
444 // determine the square of the z normal
445 nz2 = diff_xy * diff_xy / ( dx * dx + dy * dy + diff_xy * diff_xy );
446
447 // determine the z normal
448 nz = 0.0f;
449 if ( nz2 > 0.0f )
450 {
451 nz = SQRT( nz2 );
452 }
453
454 nx = - dx * nz / diff_xy;
455 ny = - dy * nz / diff_xy;
456
457 v[0] = nx;
458 v[1] = ny;
459 v[2] = nz;
460
461 return btrue;
462 }
463