/* * io-lwob.c: Morphlib I/O for LightWave[TM] Modeller files. * Copyright (C) 1999 Kuba Winnicki * * by Kuba Winnicki * * LightWave[TM] is trademark of NewTek Ltd. * * 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. * */ /* * "PNTS"; uint32 lenght_of_pnts_hunk; * float point_array[ lenght_of_pnts_hunk >> 2 ]; * "SRFS"; uint32 lenght_of_srfs_hunk; * char surface_names_list[ lenght_of_srfs_hunk ]; // somewhat * "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; * "...."; * "...."; * "SURF"; uint32 lenght_of_surf_hunk; * ... */ #include #include #include #include "morph.h" /* * Set stream at first element of hunk and return its lenght. * If not found return 0. */ static int morph_lwob_fetch_header( FILE* f, unsigned char* string ) { int n; unsigned char s[ 8 ]; while( 1 ) { if( fread( &s, 8, 1, f ) != 1 ) return 0; n = ( s[ 4 ] << 24 ) | ( s[ 5 ] << 16 ) | ( s[ 6 ] << 8 ) | s[ 7 ]; /* endian friendly hack */ if( strncmp( s, string, 4 ) == 0 ) return n; fseek( f, n, SEEK_CUR ); } } static int morph_lwob_fetch_short_header( FILE* f, unsigned char* string ) { int n, t; unsigned char s[ 6 ]; t = ftell( f ); while( 1 ) { if( fread( &s, 6, 1, f ) != 1 ) { fseek( f, t, SEEK_SET ); return 0; } n = ( s[ 4 ] << 8 ) | s[ 5 ]; /* endian friendly hack */ if( strncmp( s, string, 4 ) == 0 ) return n; fseek( f, n, SEEK_CUR ); } } static int morph_lwob_collect_surfaces( FILE* f ) { return 0; } /* Make triangle indices array */ static int morph_lwob_make_triangles( MorphModel* m ) { unsigned int num_faces; int i, j, hehe; short surf_num; unsigned short ix1, ix2, ix3; unsigned short* src; unsigned short** dst; m->triangle_indices = malloc( m->triangle_indices_len ); dst = malloc( m->surface_count * sizeof( short** ) ); src = m->triangle_indices; for( i = 0; i < m->surface_count; i++ ) { dst[ i ] = src; src += m->surfaces[ i ].triangle_count * 3; } num_faces = 0; src = m->polygon_indices; for( j = m->polygon_indices_len; j > 0; j -= 4 ) { i = *src++; j -= i << 1; surf_num = (short )src[ i ]; surf_num = ABS( surf_num ); ix1 = *src++; ix3 = *src++; /* printf( "%5d", i ); fflush( stdout ); */ if( i > 2 ) for( i -= 2; i > 0; i-- ) { *dst[ surf_num ]++ = ix1; *dst[ surf_num ]++ = ix2 = ix3; *dst[ surf_num ]++ = ix3 = *src++; num_faces++; } else src += i - 2; /* skip detailed poly info */ if( *(short* )src++ < 0 ) { src++; j -= 2; } } free( dst ); } MorphModel* load_model( FILE* f ) { MorphModel* m; int n, t, i, j = 1; unsigned int surf_len = 0; unsigned char* surf_names; unsigned short tmp16; unsigned long tmp32; unsigned char s[ 6 ]; int factor; m = morph_model_new( NULL ); /* Skip main header */ fseek( f, 12, SEEK_SET ); /* Count surfaces and alloc mem for their names */ j = 0; n = morph_lwob_fetch_header( f, "SRFS" ); m->surfaces = malloc( sizeof( MorphSurface ) ); m->surfaces[ 0 ].name = NULL; m->surfaces[ 0 ].next = NULL; if( n ) { surf_len = n; surf_names = malloc( n ); /* FIXME */ fread( surf_names, n, 1, f ); j = 1; t = 0; // printf( "%s\n", surf_names ); for( i = 1; i < n; i += 2 ) if( !surf_names[ i ] ) { // printf( "%d\n", j + 2 ); m->surfaces = realloc( m->surfaces, ( j + 1 ) * // wtf!? sizeof( MorphSurface ) ); m->surfaces[ j ].name = malloc( i - t + 1 ); strncpy( m->surfaces[ j ].name, &surf_names[ t ], i - t + 1 ); t = i + 1; // if( i != n - 1 ) // printf( "%s\n", &surf_names[ i + 1 ] ); printf( "%s\n", m->surfaces[ j ].name ); j++; } } m->surface_count = j; /* fprintf( stderr, "%d\n", surf_count ); */ fseek( f, 12, SEEK_SET ); /* Fetch array of vertices */ n = morph_lwob_fetch_header( f, "PNTS" ); if( n ) { m->vertices = malloc( n ); m->vertices_len = n; fread( m->vertices, n, 1, f ); M_32BW_FROM_BE( m->vertices, n ); } /* Fetch array of polygon indices */ n = morph_lwob_fetch_header( f, "POLS" ); if( n ) { m->polygon_indices = malloc( n ); m->polygon_indices_len = n; fread( m->polygon_indices, n, 1, f ); M_16BW_FROM_BE( m->polygon_indices, n ); } /* Load surface attributes */ // m->surfaces->name = surf_names; /* FIXME */ m->surfaces[ 0 ].triangle_count = 0; for( i = 1; i <= m->surface_count; i++ ) { // printf( "eeeeeeeeeeeek!\n" ); n = morph_lwob_fetch_header( f, "SURF" ); if( !n ) break; /* FIXME */ n += ftell( f ); // printf( "eeeeek? %s\n", m->surfaces[ i ].name ); /* Find a number of surface */ for( t = 0; ; t += 2 ) { fread( &surf_names[ t ], 2, 1, f ); if( !surf_names[ t + 1 ] ) break; } // printf( "eeek... %s\n", surf_names ); for( t = 1; t < m->surface_count; t++ ) if( !strcmp( surf_names, m->surfaces[ t ].name ) ) break; // printf( "eeek%2d? %s\n", t, m->surfaces[ t ].name ); /* if( m->surfaces[ i ].name ) j = strlen( m->surfaces[ i ].name ); else j = 0; j += j & 1; printf( "eek->%d\n", j ); fseek( f, j, SEEK_CUR ); */ m->surfaces[ t ].triangle_count = 0; morph_lwob_fetch_short_header( f, "COLR" ); fread( &m->surfaces[ t ].color, 4, 1, f ); /* Calc diffuse */ if( morph_lwob_fetch_short_header( f, "DIFF" ) ) { fread( &tmp16, 2, 1, f ); M_16BW_FROM_BE( &tmp16, 2 ); /* sucks */ } else tmp16 = 0x0100; if( morph_lwob_fetch_short_header( f, "VDIF" ) ) { fread( &tmp32, 4, 1, f ); M_32BW_FROM_BE( &tmp32, 4 ); /* sucks */ factor = ( *(float* )&tmp32 * 0x00800000 ); } else factor = tmp16 << 15; printf( "%d: %8x\n", t, factor ); m->surfaces[ t ]._diffuse[ 0 ] = factor * m->surfaces[ t ].color[ 0 ]; m->surfaces[ t ]._diffuse[ 1 ] = factor * m->surfaces[ t ].color[ 1 ]; m->surfaces[ t ]._diffuse[ 2 ] = factor * m->surfaces[ t ].color[ 2 ]; m->surfaces[ t ]._diffuse[ 3 ] = 0x7fffffff; /* Calc specular */ if( morph_lwob_fetch_short_header( f, "SPEC" ) ) { fread( &tmp16, 2, 1, f ); M_16BW_FROM_BE( &tmp16, 2 ); /* sucks */ } else tmp16 = 0x0100; if( morph_lwob_fetch_short_header( f, "VSPC" ) ) { fread( &tmp32, 4, 1, f ); M_32BW_FROM_BE( &tmp32, 4 ); /* sucks */ factor = ( *(float* )&tmp32 * 0x00800000 ); } else factor = tmp16 << 15; //printf( "%d: %8x\n", t, factor ); m->surfaces[ t ]._specular[ 0 ] = factor * m->surfaces[ t ].color[ 0 ]; m->surfaces[ t ]._specular[ 1 ] = factor * m->surfaces[ t ].color[ 1 ]; m->surfaces[ t ]._specular[ 2 ] = factor * m->surfaces[ t ].color[ 2 ]; m->surfaces[ t ]._specular[ 3 ] = 0x7fffffff; /* Calc shininess */ morph_lwob_fetch_short_header( f, "GLOS" ); fread( &tmp16, 2, 1, f ); M_16BW_FROM_BE( &tmp16, 2 ); /* likewise */ m->surfaces[ t ].specular_exp = tmp16 >> 3; fseek( f, n, SEEK_SET ); } free( surf_names ); /* We don't need that at all now */ /* Calc how much triangles we'll have */ for( i = 0; i < m->polygon_indices_len >> 1; i += 2 + n) { n = m->polygon_indices[ i ]; m->surfaces[ ABS( (short )m->polygon_indices[ i + n + 1 ] ) ].triangle_count += n - 2; m->triangle_indices_len += 6 * ( n - 2 ); if( (short )m->polygon_indices[ i + n + 1 ] < 0 ) i++; } /* debug */ /* for( i = 1; i <= m->surface_count; i++ ) printf( "%d\n", m->surfaces[ i ].triangle_count ); */ morph_lwob_make_triangles( m ); /* Way out is through */ return m; }