1303 lines
31 KiB
C
1303 lines
31 KiB
C
/*
|
|
* Copyright (c) 2007 Gero Mueller <gero.mueller@cloo.de>
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
*
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
*
|
|
* 3. This notice may not be removed or altered from any source
|
|
* distribution.
|
|
*/
|
|
|
|
#include "tl3ds.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
typedef enum tl3dsParsingState
|
|
{
|
|
TDS_STATE_READ_CHUNK_ID,
|
|
TDS_STATE_READ_CHUNK_LENGTH,
|
|
TDS_STATE_READ_OBJECT_NAME,
|
|
TDS_STATE_SKIP_CHUNK,
|
|
TDS_STATE_READ_POINT_COUNT,
|
|
TDS_STATE_READ_POINTS,
|
|
TDS_STATE_READ_TEXCOORD_COUNT,
|
|
TDS_STATE_READ_TEXCOORDS,
|
|
TDS_STATE_READ_FACE_COUNT,
|
|
TDS_STATE_READ_FACES,
|
|
TDS_STATE_READ_MATERIAL_NAME,
|
|
TDS_STATE_READ_MATERIAL_COLOR,
|
|
TDS_STATE_READ_MATERIAL_PROPERTY,
|
|
TDS_STATE_READ_MATERIAL_LIST_NAME,
|
|
TDS_STATE_READ_MATERIAL_LIST_COUNT,
|
|
TDS_STATE_READ_MATERIAL_LIST,
|
|
TDS_STATE_READ_MAP_NAME,
|
|
TDS_STATE_DONE
|
|
} tl3dsParsingState;
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
typedef struct tl3dsObject
|
|
{
|
|
char *name;
|
|
unsigned int index, count;
|
|
} tl3dsObject;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
typedef struct tl3dsMaterial
|
|
{
|
|
char *name;
|
|
float ambient[4], diffuse[4], specular[4], shininess;
|
|
} tl3dsMaterial;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
typedef struct tl3dsMaterialReference
|
|
{
|
|
char *name;
|
|
unsigned int face_index, face_count;
|
|
} tl3dsMaterialReference;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
struct tl3dsState
|
|
{
|
|
unsigned short chunk_id;
|
|
unsigned int chunk_length;
|
|
|
|
char *buffer;
|
|
unsigned int buffer_size;
|
|
unsigned int buffer_length;
|
|
|
|
unsigned int counter;
|
|
unsigned int item_count;
|
|
|
|
tl3dsParsingState parsing_state;
|
|
|
|
float *point_buffer;
|
|
unsigned int point_buffer_size;
|
|
unsigned int point_count;
|
|
unsigned int last_point_index;
|
|
|
|
float *texcoord_buffer;
|
|
unsigned int texcoord_buffer_size;
|
|
unsigned int texcoord_count;
|
|
|
|
unsigned short *face_buffer;
|
|
unsigned int face_buffer_size;
|
|
unsigned int face_count;
|
|
|
|
tl3dsMaterial *material_buffer;
|
|
unsigned int material_count;
|
|
|
|
tl3dsMaterialReference *material_reference_buffer;
|
|
unsigned int material_reference_count;
|
|
unsigned int last_material_face;
|
|
|
|
tl3dsObject **object_buffer;
|
|
unsigned int object_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static unsigned int tds_le()
|
|
{
|
|
const char endian[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
|
|
unsigned int i = *((unsigned int *)endian);
|
|
|
|
/* LE uint64: i = 1 */
|
|
/* LE uint32: i = 1 */
|
|
/* LE uint16: i = 1 */
|
|
|
|
/* BE uint32: i > 1 */
|
|
/* BE uint32: i > 1 */
|
|
/* BE uint16: i > 1 */
|
|
|
|
if( i == 1 )
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static float tds_read_le_float( const char *ptr )
|
|
{
|
|
float f = 0;
|
|
char *fptr = (char *)&f;
|
|
|
|
if( tds_le() )
|
|
{
|
|
fptr[0] = ptr[0];
|
|
fptr[1] = ptr[1];
|
|
fptr[2] = ptr[2];
|
|
fptr[3] = ptr[3];
|
|
}
|
|
else
|
|
{
|
|
fptr[0] = ptr[3];
|
|
fptr[1] = ptr[2];
|
|
fptr[2] = ptr[1];
|
|
fptr[3] = ptr[0];
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static unsigned short tds_read_le_ushort( const char *ptr )
|
|
{
|
|
unsigned short s = 0;
|
|
char *sptr = (char *)&s;
|
|
|
|
if( tds_le() )
|
|
{
|
|
sptr[0] = ptr[0];
|
|
sptr[1] = ptr[1];
|
|
}
|
|
else
|
|
{
|
|
sptr[0] = ptr[1];
|
|
sptr[1] = ptr[0];
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static unsigned int tds_read_le_uint( const char *ptr )
|
|
{
|
|
unsigned int i = 0;
|
|
char *iptr = (char *)&i;
|
|
|
|
if( tds_le() )
|
|
{
|
|
iptr[0] = ptr[0];
|
|
iptr[1] = ptr[1];
|
|
iptr[2] = ptr[2];
|
|
iptr[3] = ptr[3];
|
|
}
|
|
else
|
|
{
|
|
iptr[0] = ptr[3];
|
|
iptr[1] = ptr[2];
|
|
iptr[2] = ptr[1];
|
|
iptr[3] = ptr[0];
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int tds_buffer_reserve( tl3dsState *state, unsigned int size )
|
|
{
|
|
unsigned int new_size = 1;
|
|
char *new_buffer = 0;
|
|
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( state->buffer_size >= size )
|
|
return 0;
|
|
|
|
while( new_size < size )
|
|
new_size = new_size * 2;
|
|
|
|
new_buffer = (char *)realloc( state->buffer, new_size );
|
|
if( new_buffer )
|
|
{
|
|
state->buffer = new_buffer;
|
|
state->buffer_size = new_size;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_buffer_add( tl3dsState *state, char c )
|
|
{
|
|
if( tds_buffer_reserve( state, state->buffer_length + 1 ) != 0 )
|
|
return;
|
|
|
|
state->buffer[ state->buffer_length ] = c;
|
|
state->buffer_length++;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_material_buffer_add( tl3dsState *state, char *name )
|
|
{
|
|
float defAmbient[4] = {1.0, 1.0, 1.0, 1.0};
|
|
float defSpecular[4] = {0.0, 0.0, 0.0, 1.0};
|
|
unsigned int new_size = (state->material_count + 1 ) * sizeof(tl3dsMaterial);
|
|
tl3dsMaterial *new_buffer = realloc( state->material_buffer, new_size );
|
|
|
|
if( new_buffer == NULL )
|
|
return;
|
|
|
|
state->material_buffer = new_buffer;
|
|
state->material_buffer[state->material_count].name = malloc( strlen( name ) + 1 );
|
|
strcpy(state->material_buffer[state->material_count].name, name);
|
|
|
|
memcpy(state->material_buffer[state->material_count].ambient, defAmbient, sizeof(float) * 4);
|
|
memcpy(state->material_buffer[state->material_count].diffuse, defAmbient, sizeof(float) * 4);
|
|
memcpy(state->material_buffer[state->material_count].specular, defSpecular, sizeof(float) * 4);
|
|
state->material_buffer[state->material_count].shininess = 1.0;
|
|
|
|
state->material_count++;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_material_set_property( tl3dsState *state, float *props )
|
|
{
|
|
int last_material_index = state->material_count - 1;
|
|
|
|
switch (state->chunk_id)
|
|
{
|
|
case 0xA010:
|
|
memcpy(state->material_buffer[last_material_index].ambient, props, sizeof(float) * 3);
|
|
break;
|
|
case 0xA020:
|
|
memcpy(state->material_buffer[last_material_index].diffuse, props, sizeof(float) * 3);
|
|
break;
|
|
case 0xA030:
|
|
memcpy(state->material_buffer[last_material_index].specular, props, sizeof(float) * 3);
|
|
break;
|
|
case 0xA040:
|
|
state->material_buffer[last_material_index].shininess = *props;
|
|
break;
|
|
case 0xA050:
|
|
{
|
|
float opacity = 1.0f - *props;
|
|
|
|
state->material_buffer[last_material_index].ambient[3] = opacity;
|
|
state->material_buffer[last_material_index].diffuse[3] = opacity;
|
|
state->material_buffer[last_material_index].specular[3] = opacity;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_material_reference_buffer_add( tl3dsState *state, char *name)
|
|
{
|
|
unsigned int new_size = (state->material_reference_count + 1 ) * sizeof(tl3dsMaterialReference);
|
|
tl3dsMaterialReference *new_buffer = realloc( state->material_reference_buffer, new_size );
|
|
|
|
if( new_buffer == NULL )
|
|
return;
|
|
|
|
state->material_reference_buffer = new_buffer;
|
|
state->material_reference_buffer[state->material_reference_count].name = malloc( strlen(name) + 1 );
|
|
strcpy( state->material_reference_buffer[state->material_reference_count].name, name );
|
|
|
|
state->material_reference_count++;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_material_reference_set_range( tl3dsState *state, unsigned int face_index, unsigned int face_count )
|
|
{
|
|
if( state->material_reference_count > 0 )
|
|
{
|
|
state->material_reference_buffer[state->material_reference_count - 1].face_index = face_index;
|
|
state->material_reference_buffer[state->material_reference_count - 1].face_count = face_count;
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int tds_object_buffer_add(
|
|
tl3dsState *state,
|
|
const char *name,
|
|
unsigned int name_length )
|
|
{
|
|
tl3dsObject **new_object_buffer = 0;
|
|
unsigned int new_object_count = state->object_count + 1;
|
|
|
|
new_object_buffer = (tl3dsObject **)realloc(
|
|
state->object_buffer,
|
|
sizeof(tl3dsObject *) * new_object_count );
|
|
|
|
if( new_object_buffer )
|
|
{
|
|
/* create the new object */
|
|
tl3dsObject *new_object = (tl3dsObject *)malloc( sizeof(tl3dsObject) );
|
|
memset( new_object, 0, sizeof(tl3dsObject) );
|
|
|
|
/* copy the name */
|
|
new_object->name = (char *)malloc( name_length );
|
|
memcpy( new_object->name, name, name_length );
|
|
|
|
/* add the new object */
|
|
new_object_buffer[ new_object_count - 1 ] = new_object;
|
|
|
|
/* update state */
|
|
state->object_buffer = new_object_buffer;
|
|
state->object_count = new_object_count;
|
|
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_point_buffer_grow( tl3dsState *state, unsigned int count )
|
|
{
|
|
unsigned int new_size = (state->point_count + count ) * 3 * sizeof(float);
|
|
|
|
float *new_buffer = realloc( state->point_buffer, new_size );
|
|
if( new_buffer )
|
|
{
|
|
state->point_buffer = new_buffer;
|
|
state->point_buffer_size = new_size;
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_point_buffer_add( tl3dsState *state, float x, float y, float z )
|
|
{
|
|
unsigned int new_size = (state->point_count + 1 ) * 3 * sizeof(float);
|
|
|
|
if( state->point_buffer_size < new_size )
|
|
return;
|
|
|
|
state->point_buffer[state->point_count * 3] = x;
|
|
state->point_buffer[state->point_count * 3 + 1] = y;
|
|
state->point_buffer[state->point_count * 3 + 2] = z;
|
|
state->point_count++;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_texcoord_buffer_grow( tl3dsState *state, unsigned int count )
|
|
{
|
|
unsigned int new_size = (state->texcoord_count + count ) * 2 * sizeof(float);
|
|
float *new_buffer = realloc( state->texcoord_buffer, new_size );
|
|
|
|
if( new_buffer )
|
|
{
|
|
state->texcoord_buffer = new_buffer;
|
|
state->texcoord_buffer_size = new_size;
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_texcoord_buffer_add( tl3dsState *state, float u, float v )
|
|
{
|
|
unsigned int new_size = (state->texcoord_count + 1 ) * 2 * sizeof(float);
|
|
|
|
if( state->texcoord_buffer_size < new_size )
|
|
return;
|
|
|
|
state->texcoord_buffer[state->texcoord_count * 2] = u;
|
|
state->texcoord_buffer[state->texcoord_count * 2 + 1] = v;
|
|
state->texcoord_count++;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_face_buffer_grow( tl3dsState *state, unsigned int count )
|
|
{
|
|
unsigned int new_size
|
|
= (state->face_count + count ) * 3 * sizeof(unsigned short);
|
|
|
|
unsigned short *new_buffer = realloc( state->face_buffer, new_size );
|
|
if( new_buffer )
|
|
{
|
|
state->face_buffer = new_buffer;
|
|
state->face_buffer_size = new_size;
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void tds_face_buffer_add(
|
|
tl3dsState *state,
|
|
unsigned short a,
|
|
unsigned short b,
|
|
unsigned short c )
|
|
{
|
|
unsigned int new_size
|
|
= (state->face_count + 1 ) * 3 * sizeof(unsigned short);
|
|
|
|
if( state->face_buffer_size < new_size )
|
|
return;
|
|
|
|
state->face_buffer[state->face_count * 3] = a + state->last_point_index;
|
|
state->face_buffer[state->face_count * 3 + 1] = b + state->last_point_index;
|
|
state->face_buffer[state->face_count * 3 + 2] = c + state->last_point_index;
|
|
state->face_count++;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
tl3dsState *tl3dsCreateState()
|
|
{
|
|
tl3dsState *state = malloc( sizeof(tl3dsState) );
|
|
|
|
if( state )
|
|
{
|
|
memset( state, 0, sizeof(tl3dsState) );
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsResetState( tl3dsState *state )
|
|
{
|
|
unsigned int i;
|
|
|
|
if( state->buffer )
|
|
free( state->buffer );
|
|
|
|
if( state->object_buffer )
|
|
{
|
|
for( i = 0; i < state->object_count; i++ )
|
|
{
|
|
tl3dsObject *obj = state->object_buffer[i];
|
|
if( obj == 0 )
|
|
continue;
|
|
|
|
if( obj->name )
|
|
free( obj->name );
|
|
|
|
free( obj );
|
|
}
|
|
|
|
free( state->object_buffer );
|
|
}
|
|
|
|
if( state->point_buffer )
|
|
free( state->point_buffer );
|
|
|
|
if( state->texcoord_buffer )
|
|
free( state->texcoord_buffer );
|
|
|
|
if( state->face_buffer )
|
|
free( state->face_buffer );
|
|
|
|
if( state->material_buffer )
|
|
free( state->material_buffer );
|
|
|
|
if( state->material_reference_buffer )
|
|
free( state->material_reference_buffer );
|
|
|
|
memset( state, 0, sizeof(tl3dsState) );
|
|
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void tl3dsDestroyState( tl3dsState *state )
|
|
{
|
|
if( state )
|
|
{
|
|
tl3dsResetState( state );
|
|
free( state );
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsParse(
|
|
tl3dsState *state,
|
|
const char *buffer,
|
|
unsigned int length,
|
|
int last )
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
while( i < length )
|
|
{
|
|
char c = buffer[i];
|
|
|
|
switch( state->parsing_state )
|
|
{
|
|
case TDS_STATE_READ_CHUNK_ID:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 2 )
|
|
{
|
|
state->chunk_id = tds_read_le_ushort( state->buffer );
|
|
state->buffer_length = 0;
|
|
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_LENGTH;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_CHUNK_LENGTH:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 4 )
|
|
{
|
|
state->chunk_length = tds_read_le_uint( state->buffer );
|
|
state->buffer_length = 0;
|
|
|
|
switch( state->chunk_id )
|
|
{
|
|
case 0x4d4d: /* MAIN CHUNK */
|
|
case 0x4100: /* TRI_OBJECT */
|
|
case 0x3d3d: /* 3D EDITOR CHUNK */
|
|
case 0xAFFF: /* MATERIAL CHUNK */
|
|
case 0xA200: /* MAT_TEXMAP */
|
|
case 0xA230: /* MAT_BUMPMAP */
|
|
case 0xA33A: /* MAT_TEX2MAP */
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
break;
|
|
|
|
case 0x4000: /* OBJECT */
|
|
state->parsing_state = TDS_STATE_READ_OBJECT_NAME;
|
|
break;
|
|
|
|
case 0x4110: /* POINT_ARRAY */
|
|
state->parsing_state = TDS_STATE_READ_POINT_COUNT;
|
|
break;
|
|
|
|
case 0x4111: /* POINT_FLAG_ARRAY */
|
|
state->counter = 6;
|
|
state->parsing_state = TDS_STATE_SKIP_CHUNK;
|
|
break;
|
|
|
|
case 0x4120: /* FACE_ARRAY */
|
|
state->parsing_state = TDS_STATE_READ_FACE_COUNT;
|
|
break;
|
|
|
|
case 0x4130: /* MSH_MAT_GROUP */
|
|
state->parsing_state = TDS_STATE_READ_MATERIAL_LIST_NAME;
|
|
break;
|
|
|
|
case 0x4140: /* TEX_ARRAY */
|
|
state->parsing_state = TDS_STATE_READ_TEXCOORD_COUNT;
|
|
break;
|
|
|
|
case 0x4150: /* SMOOTH_GROUP */
|
|
state->counter = 6;
|
|
state->parsing_state = TDS_STATE_SKIP_CHUNK;
|
|
|
|
case 0x4160: /* MESH_MATRIX */
|
|
state->counter = 6;
|
|
state->parsing_state = TDS_STATE_SKIP_CHUNK;
|
|
break;
|
|
|
|
case 0xA000: /* MATERIAL_NAME */
|
|
state->parsing_state = TDS_STATE_READ_MATERIAL_NAME;
|
|
break;
|
|
|
|
case 0xA010: /* AMBIENT_COLOR */
|
|
case 0xA020: /* DIFFUSE_COLOR */
|
|
case 0xA030: /* SPECULAR_COLOR */
|
|
state->parsing_state = TDS_STATE_READ_MATERIAL_COLOR;
|
|
break;
|
|
|
|
case 0xA040: /* SHININESS */
|
|
case 0xA050: /* TRASPARENCY */
|
|
state->parsing_state = TDS_STATE_READ_MATERIAL_PROPERTY;
|
|
break;
|
|
|
|
case 0xA300: /* MAT_MAPNAME */
|
|
state->parsing_state = TDS_STATE_READ_MAP_NAME;
|
|
break;
|
|
|
|
default:
|
|
state->counter = 6;
|
|
if( state->counter >= state->chunk_length )
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
else
|
|
state->parsing_state = TDS_STATE_SKIP_CHUNK;
|
|
break;
|
|
}
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_OBJECT_NAME:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( c == 0 )
|
|
{
|
|
tds_object_buffer_add(
|
|
state,
|
|
state->buffer,
|
|
state->buffer_length );
|
|
|
|
/* continue with chunks */
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
state->buffer_length = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_POINT_COUNT:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 2 )
|
|
{
|
|
state->item_count = tds_read_le_ushort( state->buffer );
|
|
tds_point_buffer_grow( state, state->item_count );
|
|
|
|
state->parsing_state = TDS_STATE_READ_POINTS;
|
|
state->buffer_length = 0;
|
|
state->counter = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_POINTS:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 12 )
|
|
{
|
|
tds_point_buffer_add(
|
|
state,
|
|
tds_read_le_float( state->buffer ),
|
|
tds_read_le_float( state->buffer + 4 ),
|
|
tds_read_le_float( state->buffer + 8 ) );
|
|
|
|
state->counter++;
|
|
state->buffer_length = 0;
|
|
|
|
if( state->counter >= state->item_count )
|
|
{
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
state->buffer_length = 0;
|
|
state->last_point_index = state->point_count - state->item_count;
|
|
}
|
|
}
|
|
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_TEXCOORD_COUNT:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 2 )
|
|
{
|
|
state->item_count = tds_read_le_ushort( state->buffer );
|
|
tds_texcoord_buffer_grow( state, state->item_count );
|
|
|
|
state->parsing_state = TDS_STATE_READ_TEXCOORDS;
|
|
state->buffer_length = 0;
|
|
state->counter = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_TEXCOORDS:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 8 )
|
|
{
|
|
tds_texcoord_buffer_add(
|
|
state,
|
|
tds_read_le_float( state->buffer ),
|
|
tds_read_le_float( state->buffer + 4 ) );
|
|
|
|
state->counter++;
|
|
state->buffer_length = 0;
|
|
|
|
if( state->counter >= state->item_count )
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
}
|
|
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_FACE_COUNT:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 2 )
|
|
{
|
|
state->item_count = tds_read_le_ushort( state->buffer );
|
|
tds_face_buffer_grow( state, state->item_count );
|
|
|
|
state->object_buffer[state->object_count-1]->count
|
|
= state->item_count;
|
|
|
|
if( state->object_count > 1 )
|
|
state->object_buffer[state->object_count - 1]->index
|
|
= state->object_buffer[state->object_count-2]->index
|
|
+ state->object_buffer[state->object_count-2]->count;
|
|
|
|
|
|
state->parsing_state = TDS_STATE_READ_FACES;
|
|
state->buffer_length = 0;
|
|
state->counter = 0;
|
|
|
|
if( state->counter >= state->item_count )
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
}
|
|
++i;
|
|
|
|
break;
|
|
|
|
case TDS_STATE_READ_FACES:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 8 )
|
|
{
|
|
tds_face_buffer_add(
|
|
state,
|
|
tds_read_le_ushort( state->buffer ),
|
|
tds_read_le_ushort( state->buffer + 2),
|
|
tds_read_le_ushort( state->buffer + 4 ) );
|
|
|
|
state->counter++;
|
|
state->buffer_length = 0;
|
|
|
|
if( state->counter >= state->item_count )
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
}
|
|
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MATERIAL_NAME:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( c == 0 )
|
|
{
|
|
tds_material_buffer_add(state, state->buffer);
|
|
|
|
/* continue with chunks */
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
state->buffer_length = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MATERIAL_COLOR:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == state->chunk_length - 6 )
|
|
{
|
|
float color[3];
|
|
|
|
if( state->buffer[0] == 0x10 )
|
|
{
|
|
color[0] = tds_read_le_float( state->buffer + 6 );
|
|
color[1] = tds_read_le_float( state->buffer + 10 );
|
|
color[2] = tds_read_le_float( state->buffer + 14 );
|
|
}
|
|
else if( state->buffer[0] == 0x11 )
|
|
{
|
|
color[0] = (float)((unsigned char)(state->buffer[6])) / 255.0f;
|
|
color[1] = (float)((unsigned char)(state->buffer[7])) / 255.0f;
|
|
color[2] = (float)((unsigned char)(state->buffer[8])) / 255.0f;
|
|
}
|
|
|
|
tds_material_set_property(state, color);
|
|
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
state->buffer_length = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MATERIAL_PROPERTY:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == state->chunk_length - 6 )
|
|
{
|
|
float param;
|
|
|
|
if( state->buffer[0] == 0x30 ) /* percent int */
|
|
{
|
|
unsigned short percent = tds_read_le_ushort( state->buffer + 6 );
|
|
param = (float)percent / 100.0f;
|
|
}
|
|
else if( state->buffer[0] == 0x11 ) /* percent float */
|
|
{
|
|
float percent = tds_read_le_float( state->buffer + 6 );
|
|
param = percent / 100.0f;
|
|
}
|
|
|
|
tds_material_set_property(state, ¶m);
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
state->buffer_length = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MATERIAL_LIST_NAME:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( c == 0 )
|
|
{
|
|
tds_material_reference_buffer_add( state, state->buffer );
|
|
|
|
/* continue with chunks */
|
|
state->parsing_state = TDS_STATE_READ_MATERIAL_LIST_COUNT;
|
|
state->buffer_length = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MATERIAL_LIST_COUNT:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 2 )
|
|
{
|
|
state->item_count = tds_read_le_ushort( state->buffer );
|
|
tds_material_reference_set_range(state, state->last_material_face, state->item_count);
|
|
state->last_material_face += state->item_count;
|
|
|
|
state->parsing_state = TDS_STATE_READ_MATERIAL_LIST;
|
|
state->buffer_length = 0;
|
|
state->counter = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MATERIAL_LIST:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( state->buffer_length == 2 )
|
|
{
|
|
/* we don't care about the actual face list, we assume that materials refs come in the right order */
|
|
state->counter++;
|
|
state->buffer_length = 0;
|
|
|
|
if( state->counter >= state->item_count )
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_READ_MAP_NAME:
|
|
tds_buffer_add( state, c );
|
|
|
|
if( c == 0 )
|
|
{
|
|
/* continue with chunks */
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
state->buffer_length = 0;
|
|
}
|
|
++i;
|
|
break;
|
|
|
|
case TDS_STATE_SKIP_CHUNK:
|
|
++i;
|
|
++state->counter;
|
|
if( state->counter >= state->chunk_length )
|
|
state->parsing_state = TDS_STATE_READ_CHUNK_ID;
|
|
break;
|
|
|
|
default:
|
|
++i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( last )
|
|
state->parsing_state = TDS_STATE_DONE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsObjectCount( tl3dsState *state )
|
|
{
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return 0;
|
|
|
|
return state->object_count;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
const char *tl3dsObjectName( tl3dsState *state, unsigned int object )
|
|
{
|
|
if( state == NULL )
|
|
return NULL;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return NULL;
|
|
|
|
if( object >= state->object_count )
|
|
return NULL;
|
|
|
|
return state->object_buffer[object]->name;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsObjectFaceCount( tl3dsState *state, unsigned int object )
|
|
{
|
|
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return 0;
|
|
|
|
if( object >= state->object_count )
|
|
return 0;
|
|
|
|
return state->object_buffer[object]->count;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsObjectFaceIndex( tl3dsState *state, unsigned int object )
|
|
{
|
|
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return 0;
|
|
|
|
if( object >= state->object_count )
|
|
return 0;
|
|
|
|
return state->object_buffer[object]->index;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsMaterialCount( tl3dsState *state )
|
|
{
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return 0;
|
|
|
|
return state->material_count;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
const char *tl3dsMaterialName( tl3dsState *state,
|
|
unsigned int material )
|
|
{
|
|
if( state == NULL )
|
|
return NULL;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return NULL;
|
|
|
|
if( material >= state->material_count )
|
|
return NULL;
|
|
|
|
return state->material_buffer[material].name;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsGetMaterial( tl3dsState *state,
|
|
unsigned int index,
|
|
float *ambient, float *diffuse, float *specular,
|
|
float *shininess )
|
|
{
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( index >= state->material_count )
|
|
return 1;
|
|
|
|
if( ambient )
|
|
memcpy(ambient, state->material_buffer[index].ambient, sizeof(float) * 4);
|
|
|
|
if( diffuse )
|
|
memcpy(diffuse, state->material_buffer[index].diffuse, sizeof(float) * 4);
|
|
|
|
if( specular )
|
|
memcpy(specular, state->material_buffer[index].specular, sizeof(float) * 4);
|
|
|
|
if( shininess )
|
|
*shininess = state->material_buffer[index].shininess;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsMaterialReferenceCount( tl3dsState *state )
|
|
{
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
return state->material_reference_count;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
const char *tl3dsMaterialReferenceName( tl3dsState *state,
|
|
unsigned int object )
|
|
{
|
|
if( state == NULL )
|
|
return NULL;
|
|
|
|
if( object >= state->material_reference_count )
|
|
return NULL;
|
|
|
|
return state->material_reference_buffer[object].name;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsGetMaterialReference( tl3dsState *state,
|
|
unsigned int index,
|
|
unsigned int *face_index,
|
|
unsigned int *face_count)
|
|
{
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( index >= state->material_reference_count )
|
|
return 1;
|
|
|
|
if( face_index )
|
|
*face_index = state->material_reference_buffer[index].face_index;
|
|
|
|
if( face_count )
|
|
*face_count = state->material_reference_buffer[index].face_count;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsVertexCount( tl3dsState *state )
|
|
{
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
if( state->parsing_state != TDS_STATE_DONE )
|
|
return 0;
|
|
|
|
return state->point_count;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsGetVertexDouble(
|
|
tl3dsState *state,
|
|
unsigned int index,
|
|
double *x, double *y, double *z,
|
|
double *tu, double *tv,
|
|
double *nx, double *ny, double *nz )
|
|
{
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( index >= state->point_count )
|
|
return 1;
|
|
|
|
if( state->point_buffer && index < state->point_count )
|
|
{
|
|
if( x )
|
|
*x = (float)state->point_buffer[ index * 3 ];
|
|
|
|
if( y )
|
|
*y = (float)state->point_buffer[ index * 3 + 1];
|
|
|
|
if( z )
|
|
*z = (float)state->point_buffer[ index * 3 + 2];
|
|
}
|
|
|
|
if( state->texcoord_buffer && index < state->texcoord_count )
|
|
{
|
|
if( tu )
|
|
*tu = (float)state->texcoord_buffer[ index * 2 ];
|
|
|
|
if( tv )
|
|
*tv = (float)state->texcoord_buffer[ index * 2 + 1];
|
|
}
|
|
|
|
if( nx )
|
|
*nx = 0;
|
|
|
|
if( ny )
|
|
*ny = 0;
|
|
|
|
if( nz )
|
|
*nz = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsGetVertex(
|
|
tl3dsState *state,
|
|
unsigned int index,
|
|
float *x, float *y, float *z,
|
|
float *tu, float *tv,
|
|
float *nx, float *ny, float *nz )
|
|
{
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( index >= state->point_count )
|
|
return 1;
|
|
|
|
if( state->point_buffer && index < state->point_count )
|
|
{
|
|
if( x )
|
|
*x = (float)state->point_buffer[ index * 3 ];
|
|
|
|
if( y )
|
|
*y = (float)state->point_buffer[ index * 3 + 1];
|
|
|
|
if( z )
|
|
*z = (float)state->point_buffer[ index * 3 + 2];
|
|
}
|
|
|
|
if( state->texcoord_buffer && index < state->texcoord_count )
|
|
{
|
|
if( tu )
|
|
*tu = (float)state->texcoord_buffer[ index * 2 ];
|
|
|
|
if( tv )
|
|
*tv = (float)state->texcoord_buffer[ index * 2 + 1];
|
|
}
|
|
|
|
if( nx )
|
|
*nx = 0;
|
|
|
|
if( ny )
|
|
*ny = 0;
|
|
|
|
if( nz )
|
|
*nz = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsFaceCount( tl3dsState *state )
|
|
{
|
|
if( state == NULL )
|
|
return 0;
|
|
|
|
return state->face_count;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsGetFaceInt(
|
|
tl3dsState *state,
|
|
unsigned int index,
|
|
unsigned int *a,
|
|
unsigned int *b,
|
|
unsigned int *c )
|
|
{
|
|
unsigned int face = 0;
|
|
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( state->face_buffer && face <= state->face_count )
|
|
{
|
|
if( a )
|
|
*a = state->face_buffer[ index * 3 ];
|
|
|
|
if( b )
|
|
*b = state->face_buffer[ index * 3 + 1 ];
|
|
|
|
if( c )
|
|
*c = state->face_buffer[ index * 3 + 2 ];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsGetFace(
|
|
tl3dsState *state,
|
|
unsigned int index,
|
|
unsigned short *a,
|
|
unsigned short *b,
|
|
unsigned short *c )
|
|
{
|
|
unsigned int face = 0;
|
|
|
|
if( state == NULL )
|
|
return 1;
|
|
|
|
if( state->face_buffer && face <= state->face_count )
|
|
{
|
|
if( a )
|
|
*a = state->face_buffer[ index * 3 ];
|
|
|
|
if( b )
|
|
*b = state->face_buffer[ index * 3 + 1 ];
|
|
|
|
if( c )
|
|
*c = state->face_buffer[ index * 3 + 2 ];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int tl3dsCheckFileExtension( const char *filename )
|
|
{
|
|
const char *ext = 0, *tmp = filename;
|
|
|
|
if( filename == NULL )
|
|
return 1;
|
|
|
|
while( *tmp != 0 )
|
|
{
|
|
if( *tmp == '.' )
|
|
ext = tmp + 1;
|
|
|
|
tmp++;
|
|
}
|
|
|
|
/* no extension found */
|
|
if( ext == 0 )
|
|
return 1;
|
|
|
|
if( (ext[0] == '3')
|
|
&& (ext[1] == 'd' || ext[1] == 'D')
|
|
&& (ext[2] == 's' || ext[2] == 'S')
|
|
&& (ext[3] == 0) )
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
unsigned int tl3dsHasNormals( tl3dsState *state )
|
|
{
|
|
return 0;
|
|
}
|