/* * io-3ds.c: Morphlib loader for 3D Studio[TM] files. * 3D Studio[TM] is trademark of Autodesk Ltd. * * by Kuba Winnicki * * Copyright (C) 1999 Kuba Winnicki * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA. * */ /* * Chunk tree: * * 0x4d4d -- Main * 0x3d3d -- Edit * 0x4000 -- Object * 0x4100 -- TriMesh * 0x4110 -- Triangle Vertices * 0x4120 -- Triangle Indices * * "PNTS"; uint32 lenght_of_pnts_hunk; * float point_array[lenght_of_pnts_hunk >> 2]; * "SRFS"; uint32 lenght_of_srfs_hunk; * ... * "POLS"; uint32 lenght_of_pols_hunk; * uint16 num_pnts_in_poly; * uint16 indices[num_pnts_in_poly]; * uint16 surface; * "SURF"; uint32 lenght_of_surf_hunk; * ... */ /* * Note: This routine holds a lot of crap. It will be rewritten. */ #include #include #include #include "morph.h" /* * Set stream at first element of chunk and return its lenght. * If not found return 0. */ /* FIXME endianess! */ static int morph_3ds_find_chunk( FILE* f, unsigned short* path, unsigned long seekpos ) { int chunk_len; unsigned short chunk_id; if( !*path ) return 0; while( fread( &chunk_id, 2, 1, f ) == 1 ) { fread( &chunk_len, 4, 1, f ); printf( "%8x: \"%04x\" %8x/%d ", ftell( f ), chunk_id, chunk_len, chunk_len ); if( chunk_id != *path ) { if( fseek( f, chunk_len - 6, SEEK_CUR ) ) { printf( "not found\n" ); return 0; } printf( "skipping\n" ); } else { path++; if( !*path ) { printf( "found\n" ); return chunk_len; } else printf( "entering node\n" ); } if( seekpos && ( ftell( f ) >= seekpos ) ) break; } return 0; } static void morph_3ds_load_chunks( MorphModel* m, FILE* f, unsigned long* chunk_buf ) { unsigned long indices_displace = 0, chunk_len; unsigned short screw; int i, t = 0; float* vertices = m->vertices; unsigned short* indices = m->triangle_indices; unsigned short** ind_tab; unsigned long* ind_tab_hack; unsigned long* tmp_buf; ind_tab = calloc( m->surface_count + 1, sizeof( short* ) ); ind_tab_hack = ( unsigned long* )ind_tab; /* Calc addresses to load stuff -- FIXME unportable hack */ tmp_buf = chunk_buf; while( *tmp_buf ) { tmp_buf += 3; i = *tmp_buf++; while( ( t = *tmp_buf++ ) >= 0 ) { // t = *tmp_buf++; i = *tmp_buf++; ind_tab_hack[ t + 1 ] += i * 6; printf( "%d %d\n", t, i ); } } ind_tab[ 0 ] = m->triangle_indices; for( i = 1; i < m->surface_count; i++ ) { ind_tab_hack[ i ] += ind_tab_hack[ i - 1 ]; printf( "%x\n", ind_tab[ i - 1 ] ); } /* Load stuff */ while( *chunk_buf ) { fseek( f, *chunk_buf++, SEEK_SET ); chunk_len = *chunk_buf++; // printf( "%x %x\n", ftell( f ), ftell( f ) + chunk_len ); fread( vertices, chunk_len, 1, f ); M_32BW_FROM_LE( vertices, chunk_len ); vertices += chunk_len >> 2; fseek( f, *chunk_buf++, SEEK_SET ); i = *chunk_buf++; printf( "%d\n", *chunk_buf ); if( *chunk_buf == -1 ) { m->surfaces[ 0 ].triangle_count += i >> 3; printf( "Using default material\n" ); } while( ( t = *chunk_buf++ ) >= 0 ) { // t = *chunk_buf++; i = *chunk_buf++; // chunk_buf++; //skip /* printf( "eee... %d ...eek\n", m->surfaces[ t ].triangle_count ); */ m->surfaces[ t ].triangle_count += i; printf( "Object %d has %d triangles\n", t, m->surfaces[ t ].triangle_count ); printf( "and uses surface %d\n", t ); for( ; i > 0; i-- ) { fread( ind_tab[ t ], 6, 1, f ); fread( &screw, 2, 1, f );//fseek( f, 2, SEEK_CUR ); // printf( "%x:", screw & 0x7 ); M_16BW_FROM_LE( ind_tab[ t ], 6 ); *ind_tab[ t ]++ += indices_displace; *ind_tab[ t ]++ += indices_displace; *ind_tab[ t ]++ += indices_displace; } // printf( "%d\n", *( chunk_buf - 1 ) ); } indices_displace += chunk_len / 12; t++; } free( ind_tab ); } static unsigned long* morph_3ds_get_surface_info( MorphModel* m, FILE* f, unsigned long seekpos, unsigned long* chunk_buf, unsigned char* surfname ) { int i; unsigned short materpath[] = { 0x4130, 0 }; unsigned long t, len, tmp; unsigned long* tmp_buf; printf( "%x\n", seekpos ); tmp_buf = chunk_buf; while( ( len = morph_3ds_find_chunk( f, materpath, seekpos ) ) ) { i = 0; do { t = fgetc( f ); surfname[ i++ ] = t; } while( t ); printf( "%s\n", surfname ); for( t = 0; t < m->surface_count; t++ ) if( !strcmp( surfname, m->surfaces[ t ].name ) ) break; *chunk_buf++ = t; tmp = 0; fread( &tmp, 2, 1, f ); M_32BW_FROM_LE( &tmp, 4 ); *chunk_buf++ = tmp; fseek( f, len - 8 - i, SEEK_CUR ); } if( tmp_buf == chunk_buf ) { *chunk_buf++ = 0; *chunk_buf++ = *( chunk_buf - 2 ) >> 3; } *chunk_buf++ = -1; return chunk_buf; } MorphModel* load_model( FILE* f ) { MorphModel* m; /* * These are "paths" to certain chunks * when we'll be finished, make it flat and change to #define's * or something */ unsigned short meshpath[] = { 0x4d4d, 0x3d3d, 0 }, //0x4000, 0 }, surfpath[] = { 0xafff, 0 }, snamepath[] = { 0xa000, 0 }, diffpath[] = { 0xa020, 0 }, specpath[] = { 0xa030, 0 }, shinepath[] = { 0xa040, 0 }, rgbpath[] = { 0x0011, 0 }, percpath[] = { 0x0030, 0 }, objpath[] = { 0x4000, 0 }, vertpath[] = { 0x4100, 0x4110, 0 }, facepath[] = { 0x4120, 0 }, materpath[] = { 0x4130, 0 }; unsigned char* surfname; unsigned long len, seekpos, seekobj, num_objects = 0, t; unsigned short id, vertice_count, triangle_count; unsigned long* chunk_buf_ptr, * chunk_buf; unsigned char color[ 4 ]; int i; unsigned long max_name_len = 1; unsigned char* k; m = morph_model_new( NULL ); morph_3ds_find_chunk( f, meshpath, 0 ); seekobj = ftell( f ); t = 0; m->surfaces = calloc( 1, sizeof( MorphSurface ) ); /* Collect surface materials */ while( len = morph_3ds_find_chunk( f, surfpath, 0 ) ) { seekpos = ftell( f ) - 6 + len; m->surfaces = realloc( m->surfaces, ( t + 1 ) * sizeof( MorphSurface ) ); m->surfaces[ t ].triangle_count = 0; len = morph_3ds_find_chunk( f, snamepath, 0 ); m->surfaces[ t ].name = malloc( len ); fread( m->surfaces[ t ].name, len, 1, f ); printf( "%s\n", m->surfaces[ t ].name ); if( max_name_len < len ) max_name_len = len; m->surfaces[ t ].flags = MORPH_DBL_SIDE; morph_3ds_find_chunk( f, diffpath, 0 ); morph_3ds_find_chunk( f, rgbpath, 0 ); fread( color, 3, 1, f ); m->surfaces[ t ]._diffuse[ 0 ] = color[ 0 ] << 23; m->surfaces[ t ]._diffuse[ 1 ] = color[ 1 ] << 23; m->surfaces[ t ]._diffuse[ 2 ] = color[ 2 ] << 23; m->surfaces[ t ]._diffuse[ 3 ] = 0x7fffffff; morph_3ds_find_chunk( f, specpath, 0 ); morph_3ds_find_chunk( f, rgbpath, 0 ); fread( color, 3, 1, f ); m->surfaces[ t ]._specular[ 0 ] = color[ 0 ] << 23; m->surfaces[ t ]._specular[ 1 ] = color[ 1 ] << 23; m->surfaces[ t ]._specular[ 2 ] = color[ 2 ] << 23; m->surfaces[ t ]._specular[ 3 ] = 0x7fffffff; morph_3ds_find_chunk( f, shinepath, 0 ); if( morph_3ds_find_chunk( f, percpath, seekpos ) ) { m->surfaces[ t ].specular_exp = 0; fread( &m->surfaces[ t ].specular_exp, 2, 1, f ); M_32BW_FROM_LE( &m->surfaces[ t ].specular_exp, 4 ); } else m->surfaces[ t ].specular_exp = 128; m->surfaces[ t ].next = NULL; t++; } printf( "%d materials\n", t ); if( !t ) { t = 1; printf( "Generating default material\n" ); m->surfaces[ 0 ]._diffuse[ 0 ] = 0x3fffffff; m->surfaces[ 0 ]._diffuse[ 1 ] = 0x3fffffff; m->surfaces[ 0 ]._diffuse[ 2 ] = 0x3fffffff; m->surfaces[ 0 ]._diffuse[ 3 ] = 0x7fffffff; m->surfaces[ 0 ]._specular[ 0 ] = 0x3fffffff; m->surfaces[ 0 ]._specular[ 1 ] = 0x3fffffff; m->surfaces[ 0 ]._specular[ 2 ] = 0x3fffffff; m->surfaces[ 0 ]._specular[ 3 ] = 0x7fffffff; m->surfaces[ 0 ].specular_exp = 16; } m->surface_count = t; /* Objects -- Let the fuck up happens */ fseek( f, seekobj, SEEK_SET ); len = morph_3ds_find_chunk( f, objpath, 0 ); seekobj = ftell( f ) - 6; // m->surfaces = calloc( 1, sizeof( MorphSurface ) ); chunk_buf = chunk_buf_ptr = malloc( 1024 * 4 * 4 ); surfname = malloc( max_name_len ); while( 1 ) { fseek( f, seekobj, SEEK_SET ); len = morph_3ds_find_chunk( f, objpath, 0 ); if( !len ) break; seekpos = ftell( f ) - 6; do { seekpos += len; i = 0; do { t = fgetc( f ); // putchar( t ); surfname[ i++ ] = t; } while( t ); printf( "%s\n", surfname ); len = morph_3ds_find_chunk( f, vertpath, 0 ); if( len ) { if( num_objects++ == 256 ) break; fread( &vertice_count, 2, 1, f ); m->vertices_len += vertice_count * 12; *chunk_buf++ = ftell( f ); /* printf( "%x\n", ftell( f ) ); */ *chunk_buf++ = len -= 8; fseek( f, len, SEEK_CUR ); len = morph_3ds_find_chunk( f, facepath, 0 ); fread( &triangle_count, 2, 1, f ); m->triangle_indices_len += triangle_count * 6; *chunk_buf++ = ftell( f ); *chunk_buf++ = triangle_count * 8; fseek( f, triangle_count * 8, SEEK_CUR ); chunk_buf = morph_3ds_get_surface_info( m, f, seekpos, chunk_buf, surfname ); /* printf( "Vertices: %6d Triangles: %6d\n", vertice_count, triangle_count ); } else printf( "Not a mesh\n" ); */ } fseek( f, seekpos, SEEK_SET ); fread( &id, 2, 1, f ); fread( &len, 4, 1, f ); } while( id == 0x4000 ); seekobj = ftell( f ) - 6; } /* printf( "--------------------- Vertices: %6d, Triangles: %6d\n", vertices_len / 12, triangle_indices_len / 6 ); */ free( surfname ); *chunk_buf = 0; m->vertices = calloc( m->vertices_len * 4, 1 ); m->triangle_indices = malloc( m->triangle_indices_len ); morph_3ds_load_chunks( m, f, chunk_buf_ptr );//, // m->vertices, m->triangle_indices ); // m->surfaces[ 0 ].triangle_count = m->triangle_indices_len / 6; // printf( "eeeeeeeeek! which means we have %d all tris! eee*bang*\n", // m->triangle_indices_len / 6 ); free( chunk_buf_ptr ); return m; }