Exemplo n.º 1
0
picoSurface_t* PicoModelFindOrAddSurface( picoModel_t *model, picoShader_t* shader )
{
	/* see if a surface already has the shader */
	int i = 0;
	for ( ; i < model->numSurfaces ; i++ )
	{
		picoSurface_t* workSurface = model->surface[i];
		if ( workSurface->shader == shader )
		{			
			return workSurface;
		}
	}

	/* no surface uses this shader yet, so create a new surface */

	{
		/* create a new surface in the model for the unique shader */
		picoSurface_t* workSurface = PicoNewSurface(model);
		if ( !workSurface )
		{
			_pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" );
			return 0;
		}

		/* do surface setup */
		PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
		PicoSetSurfaceName( workSurface, shader->name );
		PicoSetSurfaceShader( workSurface, shader );

		return workSurface;
	}
}
Exemplo n.º 2
0
/* _ms3d_load:
 *	loads a milkshape3d model file.
 */
static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){
	picoModel_t    *model;
	unsigned char  *bufptr, *bufptr0;
	int shaderRefs[ MS3D_MAX_GROUPS ];
	int numGroups;
	int numMaterials;
//	unsigned char  *ptrToGroups;
	int numVerts;
	unsigned char  *ptrToVerts;
	int numTris;
	unsigned char  *ptrToTris;
	int i,k,m;

	/* create new pico model */
	model = PicoNewModel();
	if ( model == NULL ) {
		return NULL;
	}

	/* do model setup */
	PicoSetModelFrameNum( model, frameNum );
	PicoSetModelName( model, fileName );
	PicoSetModelFileName( model, fileName );

	bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize );
	memcpy( bufptr, buffer, bufSize );
	/* skip header */
	bufptr += sizeof( TMsHeader );

	/* get number of vertices */
	bufptr = GetWord( bufptr,&numVerts );
	ptrToVerts = bufptr;

#ifdef DEBUG_PM_MS3D
	printf( "NumVertices: %d\n",numVerts );
#endif
	/* swap verts */
	for ( i = 0; i < numVerts; i++ )
	{
		TMsVertex *vertex;
		vertex = (TMsVertex *)bufptr;
		bufptr += sizeof( TMsVertex );

		vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
		vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
		vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );

#ifdef DEBUG_PM_MS3D_EX_
		printf( "Vertex: x: %f y: %f z: %f\n",
				msvd[i]->vertex[0],
				msvd[i]->vertex[1],
				msvd[i]->vertex[2] );
#endif
	}
	/* get number of triangles */
	bufptr = GetWord( bufptr,&numTris );
	ptrToTris = bufptr;

#ifdef DEBUG_PM_MS3D
	printf( "NumTriangles: %d\n",numTris );
#endif
	/* swap tris */
	for ( i = 0; i < numTris; i++ )
	{
		TMsTriangle *triangle;
		triangle = (TMsTriangle *)bufptr;
		bufptr += sizeof( TMsTriangle );

		triangle->flags = _pico_little_short( triangle->flags );

		/* run through all tri verts */
		for ( k = 0; k < 3; k++ )
		{
			/* swap tex coords */
			triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
			triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );

			/* swap fields */
			triangle->vertexIndices[ k ]      = _pico_little_short( triangle->vertexIndices[ k ] );
			triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
			triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
			triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );

			/* check for out of range indices */
			if ( triangle->vertexIndices[ k ] >= numVerts ) {
				_pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 );
				PicoFreeModel( model );
				_pico_free( bufptr0 );
				return NULL; /* yuck */
			}
		}
	}
	/* get number of groups */
	bufptr = GetWord( bufptr,&numGroups );
//	ptrToGroups = bufptr;

#ifdef DEBUG_PM_MS3D
	printf( "NumGroups: %d\n",numGroups );
#endif
	/* run through all groups in model */
	for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
	{
		picoSurface_t *surface;
		TMsGroup      *group;

		group = (TMsGroup *)bufptr;
		bufptr += sizeof( TMsGroup );

		/* we ignore hidden groups */
		if ( group->flags & MS3D_HIDDEN ) {
			bufptr += ( group->numTriangles * 2 ) + 1;
			continue;
		}
		/* forced null term of group name */
		group->name[ 31 ] = '\0';

		/* create new pico surface */
		surface = PicoNewSurface( model );
		if ( surface == NULL ) {
			PicoFreeModel( model );
			_pico_free( bufptr0 );
			return NULL;
		}
		/* do surface setup */
		PicoSetSurfaceType( surface,PICO_TRIANGLES );
		PicoSetSurfaceName( surface,group->name );

		/* process triangle indices */
		for ( k = 0; k < group->numTriangles; k++ )
		{
			TMsTriangle *triangle;
			unsigned int triangleIndex;

			/* get triangle index */
			bufptr = GetWord( bufptr,(int *)&triangleIndex );

			/* get ptr to triangle data */
			triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) );

			/* run through triangle vertices */
			for ( m = 0; m < 3; m++ )
			{
				TMsVertex   *vertex;
				unsigned int vertexIndex;
				picoVec2_t texCoord;

				/* get ptr to vertex data */
				vertexIndex = triangle->vertexIndices[ m ];
				vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) );

				/* store vertex origin */
				PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );

				/* store vertex color */
				PicoSetSurfaceColor( surface,0,vertexIndex,white );

				/* store vertex normal */
				PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );

				/* store current face vertex index */
				PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex );

				/* get texture vertex coord */
				texCoord[ 0 ] = triangle->s[ m ];
				texCoord[ 1 ] = -triangle->t[ m ];  /* flip t */

				/* store texture vertex coord */
				PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
			}
		}
		/* store material */
		shaderRefs[ i ] = *bufptr++;

#ifdef DEBUG_PM_MS3D
		printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles );
#endif
	}
	/* get number of materials */
	bufptr = GetWord( bufptr,&numMaterials );

#ifdef DEBUG_PM_MS3D
	printf( "NumMaterials: %d\n",numMaterials );
#endif
	/* run through all materials in model */
	for ( i = 0; i < numMaterials; i++ )
	{
		picoShader_t *shader;
		picoColor_t ambient,diffuse,specular;
		TMsMaterial  *material;
		int k;

		material = (TMsMaterial *)bufptr;
		bufptr += sizeof( TMsMaterial );

		/* null term strings */
		material->name    [  31 ] = '\0';
		material->texture [ 127 ] = '\0';
		material->alphamap[ 127 ] = '\0';

		/* ltrim strings */
		_pico_strltrim( material->name );
		_pico_strltrim( material->texture );
		_pico_strltrim( material->alphamap );

		/* rtrim strings */
		_pico_strrtrim( material->name );
		_pico_strrtrim( material->texture );
		_pico_strrtrim( material->alphamap );

		/* create new pico shader */
		shader = PicoNewShader( model );
		if ( shader == NULL ) {
			PicoFreeModel( model );
			_pico_free( bufptr0 );
			return NULL;
		}
		/* scale shader colors */
		for ( k = 0; k < 4; k++ )
		{
			ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 );
			diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 );
			specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 );
		}
		/* set shader colors */
		PicoSetShaderAmbientColor( shader,ambient );
		PicoSetShaderDiffuseColor( shader,diffuse );
		PicoSetShaderSpecularColor( shader,specular );

		/* set shader transparency */
		PicoSetShaderTransparency( shader,material->transparency );

		/* set shader shininess (0..127) */
		PicoSetShaderShininess( shader,material->shininess );

		/* set shader name */
		PicoSetShaderName( shader,material->name );

		/* set shader texture map name */
		PicoSetShaderMapName( shader,material->texture );

#ifdef DEBUG_PM_MS3D
		printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap );
#endif
	}
	/* assign shaders to surfaces */
	for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
	{
		picoSurface_t *surface;
		picoShader_t  *shader;

		/* sanity check */
		if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
			 shaderRefs[ i ] < 0 ) {
			continue;
		}

		/* get surface */
		surface = PicoGetModelSurface( model,i );
		if ( surface == NULL ) {
			continue;
		}

		/* get shader */
		shader = PicoGetModelShader( model,shaderRefs[ i ] );
		if ( shader == NULL ) {
			continue;
		}

		/* assign shader */
		PicoSetSurfaceShader( surface,shader );

#ifdef DEBUG_PM_MS3D
		printf( "Mapped: %d ('%s') to %d (%s)\n",
				shaderRefs[i],shader->name,i,surface->name );
#endif
	}
	/* return allocated pico model */
	_pico_free( bufptr0 );
	return model;
//	return NULL;
}
Exemplo n.º 3
0
// _fm_load() loads a Heretic 2 model file.
static picoModel_t *_fm_load( PM_PARAMS_LOAD )
{
	int				i, j, dups, dup_index;
	int				fm_file_pos;
	index_LUT_t		*p_index_LUT, *p_index_LUT2, *p_index_LUT3;
	index_DUP_LUT_t	*p_index_LUT_DUPS;

	fm_vert_normal_t	*vert;

	char			skinname[FM_SKINPATHSIZE];
 	fm_t			fm;
	fm_header_t		*fm_head;
	fm_st_t			*texCoord;
	fm_xyz_st_t		*tri_verts;
	fm_xyz_st_t		*triangle;
	fm_frame_t		*frame;

	picoByte_t      *bb, *bb0;
	picoModel_t	*picoModel;
	picoSurface_t	*picoSurface;
	picoShader_t	*picoShader;
	picoVec3_t	xyz, normal;
	picoVec2_t	st;
	picoColor_t	color;
	

	bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
	memcpy(bb, buffer, bufSize);

	// Header Header
	fm.fm_header_hdr = (fm_chunk_header_t *) bb;
	fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
	if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME))  )
	{
		_pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
	{
		_pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	// Skin Header
	fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
	fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
	if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
	{
		_pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
	{
		_pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	// ST Header
	fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
	fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
	if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
	{
		_pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
	{
		_pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	// Tris Header
	fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
	fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
	if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
	{
		_pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
	{
		_pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	// Frame Header
	fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
	fm_file_pos += sizeof(fm_chunk_header_t);
	if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
	{
		_pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
	{
		_pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
		_pico_free(bb0);
		return NULL;
	}

	// Header
	fm_file_pos = sizeof(fm_chunk_header_t);
	fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos);
	fm_file_pos += fm.fm_header_hdr->size;

	// Skin
	fm_file_pos += sizeof(fm_chunk_header_t);
	fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos);
	fm_file_pos += fm.fm_skin_hdr->size;

	// ST
	fm_file_pos += sizeof(fm_chunk_header_t);
	texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos);
	fm_file_pos += fm.fm_st_hdr->size;

	// Tri
	fm_file_pos += sizeof(fm_chunk_header_t);
	tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos);
	fm_file_pos += fm.fm_tri_hdr->size;

	// Frame
	fm_file_pos += sizeof(fm_chunk_header_t);
	frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);

	// do frame check
	if( fm_head->numFrames < 1 )
	{
		_pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
		_pico_free(bb0);
		return NULL;
	}
	
	if( frameNum < 0 || frameNum >= fm_head->numFrames )
	{
		_pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
		_pico_free(bb0);
		return NULL;
	}

	// swap fm
	fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
	fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
	fm_head->frameSize = _pico_little_long( fm_head->frameSize );

	fm_head->numSkins = _pico_little_long( fm_head->numSkins );
	fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
	fm_head->numST = _pico_little_long( fm_head->numST );
	fm_head->numTris = _pico_little_long( fm_head->numTris );
	fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
	fm_head->numFrames = _pico_little_long( fm_head->numFrames );

	// swap frame scale and translation
	for( i = 0; i < 3; i++ )
	{
		frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
		frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
	}

	// swap triangles
	triangle = tri_verts;
	for( i = 0; i < fm_head->numTris; i++, triangle++ )
	{
		for( j = 0; j < 3; j++ )
		{
			triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
			triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
		}
	}

	// swap st coords
	for( i = 0; i < fm_head->numST; i++ )
	{
		texCoord->s = _pico_little_short( texCoord[i].s );
		texCoord->t = _pico_little_short( texCoord[i].t );
	}
	// set Skin Name
	strncpy(skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );

#ifdef FM_VERBOSE_DBG
	// Print out md2 values
	_pico_printf(PICO_VERBOSE,"numSkins->%d  numXYZ->%d  numST->%d  numTris->%d  numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname );
#endif

	// detox Skin name
	_pico_setfext( skinname, "" );
	_pico_unixify( skinname );

	/* create new pico model */
	picoModel = PicoNewModel();
	if( picoModel == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
		_pico_free(bb0);
		return NULL;
	}

	/* do model setup */
	PicoSetModelFrameNum( picoModel, frameNum );
	PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
	PicoSetModelName( picoModel, fileName );
	PicoSetModelFileName( picoModel, fileName );

	// allocate new pico surface
	picoSurface = PicoNewSurface( picoModel );
	if( picoSurface == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
		PicoFreeModel( picoModel );
		_pico_free(bb0);
		return NULL;
	}


	PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
	PicoSetSurfaceName( picoSurface, frame->header.name );
	picoShader = PicoNewShader( picoModel );
	if( picoShader == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
		PicoFreeModel( picoModel );
		_pico_free(bb0);
		return NULL;
	}

	PicoSetShaderName( picoShader, skinname );

	// associate current surface with newly created shader
	PicoSetSurfaceShader( picoSurface, picoShader );

	// Init LUT for Verts
	p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ);
	for(i=0; i<fm_head->numXYZ; i++)
	{
		p_index_LUT[i].Vert = -1;
		p_index_LUT[i].ST = -1;
		p_index_LUT[i].next = NULL;
	}

	// Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
	dups = 0;
	triangle = tri_verts;

	for(i=0; i<fm_head->numTris; i++)
	{
		for(j=0; j<3; j++)
		{
			if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry
				p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];

			else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry
			{
#ifdef FM_VERBOSE_DBG
				_pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
#endif
				continue;
			}
			else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) )  // Not equal to Main entry, and no LL entry
			{	// Add first entry of LL from Main
				p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
				if (p_index_LUT2 == NULL)
					_pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
				p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
				p_index_LUT2->Vert = dups;
				p_index_LUT2->ST = triangle->index_st[j];
				p_index_LUT2->next = NULL;
#ifdef FM_VERBOSE_DBG
				_pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]);
#endif
				triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
				dups++;
			}
			else // Try to find in LL from Main Entry
			{
				p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
				while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
				{
					p_index_LUT3 = p_index_LUT2;
					p_index_LUT2 = p_index_LUT2->next;
				}
				p_index_LUT2 = p_index_LUT3;

				if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it
				{
					triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
#ifdef FM_VERBOSE_DBG
					_pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
#endif
					continue;
				}

				if ( p_index_LUT2->next == NULL)  // Didn't find it. Add entry to LL.
				{
					// Add the Entry
					p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
					if (p_index_LUT3 == NULL)
						_pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
					p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
					p_index_LUT3->Vert = dups;
					p_index_LUT3->ST = triangle->index_st[j];
					p_index_LUT3->next = NULL;
#ifdef FM_VERBOSE_DBG
					_pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]);
#endif
					triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
					dups++;
				}
			}
#ifdef FM_VERBOSE_DBG
			_pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
#endif
		}
		triangle++;
	}

	// malloc and build array for Dup STs
	p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
	if (p_index_LUT_DUPS == NULL)
		_pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");

	dup_index = 0;
	for(i=0; i<fm_head->numXYZ; i++)
	{
		p_index_LUT2 = p_index_LUT[i].next;
		while (p_index_LUT2 != NULL)
		{
			p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
			p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
			dup_index++;
			p_index_LUT2 = p_index_LUT2->next;
		}
	}
#ifdef FM_VERBOSE_DBG
	_pico_printf( PICO_NORMAL, " Dups = %d\n", dups);
	_pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index);
#endif
	for(i=0; i<fm_head->numXYZ; i++)
	{
#ifdef FM_VERBOSE_DBG
		_pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);
#endif
		if (p_index_LUT[i].next != NULL)
		{

			p_index_LUT2 = p_index_LUT[i].next;
			do {
#ifdef FM_VERBOSE_DBG
				_pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);
#endif
				p_index_LUT2 = p_index_LUT2->next;
			} while ( p_index_LUT2 != NULL);

		}
#ifdef FM_VERBOSE_DBG
		_pico_printf( PICO_NORMAL, "\n");
#endif
	}


#ifdef FM_VERBOSE_DBG
	for(i=0; i<dup_index; i++)
		_pico_printf( PICO_NORMAL, " Dup Index #%d  OldVert: %d  ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST);

	triangle = tri_verts;
	for(i=0; i<fm_head->numTris; i++)
	{
		for(j=0; j<3; j++)
			_pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
		_pico_printf( PICO_NORMAL, "\n");
		triangle++;
	}
#endif
	// Build Picomodel
	triangle = tri_verts;
	for( j = 0; j < fm_head->numTris; j++, triangle++ )
	{
		PicoSetSurfaceIndex( picoSurface, j*3   , triangle->index_xyz[0] );
		PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
		PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
	}

	vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );
	for(i=0; i< fm_head->numXYZ; i++, vert++)
	{
		/* set vertex origin */
		xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
		xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
		xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
		PicoSetSurfaceXYZ( picoSurface, i , xyz );

		/* set normal */
		normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
		normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
		normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
		PicoSetSurfaceNormal( picoSurface, i , normal );

		/* set st coords */
		st[ 0 ] =  ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth));
		st[ 1 ] =  (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight));
		PicoSetSurfaceST( picoSurface, 0, i , st );
	}

	if (dups)
	{
		for(i=0; i<dups; i++)
		{
			j = p_index_LUT_DUPS[i].OldVert;
			/* set vertex origin */
			xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
			xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
			xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
			PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz );

			/* set normal */
			normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
			normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
			normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
			PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal );

			/* set st coords */
			st[ 0 ] =  ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth));
			st[ 1 ] =  (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight));
			PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st );
		}
	}

	/* set color */
	PicoSetSurfaceColor( picoSurface, 0, 0, color );

	// Free up malloc'ed LL entries
	for(i=0; i<fm_head->numXYZ; i++)
	{
		if(p_index_LUT[i].next != NULL)
		{
			p_index_LUT2 = p_index_LUT[i].next;
			do {
				p_index_LUT3 = p_index_LUT2->next;
				_pico_free(p_index_LUT2);
				p_index_LUT2 = p_index_LUT3;
				dups--;
			} while (p_index_LUT2 != NULL);
		}
	}

	if (dups)
		_pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");

	// Free malloc'ed LUTs
 	_pico_free(p_index_LUT);
	_pico_free(p_index_LUT_DUPS);

	/* return the new pico model */
	_pico_free(bb0);
	return picoModel;

}
Exemplo n.º 4
0
static picoModel_t *_terrain_load( PM_PARAMS_LOAD ){
	int i, j, v, pw[ 5 ], r;
	picoParser_t    *p;

	char            *shader, *heightmapFile, *colormapFile;
	picoVec3_t scale, origin;

	unsigned char   *imageBuffer;
	int imageBufSize, w, h, cw, ch;
	unsigned char   *heightmap, *colormap, *heightPixel, *colorPixel;

	picoModel_t     *picoModel;
	picoSurface_t   *picoSurface;
	picoShader_t    *picoShader;
	picoVec3_t xyz, normal;
	picoVec2_t st;
	picoColor_t color;


	/* create pico parser */
	p = _pico_new_parser( (const picoByte_t*) buffer, bufSize );
	if ( p == NULL ) {
		return NULL;
	}

	/* get first token */
	if ( _pico_parse_first( p ) == NULL ) {
		return NULL;
	}

	/* check first token */
	if ( _pico_stricmp( p->token, "picoterrain" ) ) {
		_pico_printf( PICO_ERROR, "Invalid PicoTerrain model" );
		_pico_free_parser( p );
		return NULL;
	}

	/* setup */
	shader = heightmapFile = colormapFile = NULL;
	_pico_set_vec( scale, 512, 512, 32 );

	/* parse ase model file */
	while ( 1 )
	{
		/* get first token on line */
		if ( !_pico_parse_first( p ) ) {
			break;
		}

		/* skip empty lines */
		if ( !p->token || !p->token[ 0 ] ) {
			continue;
		}

		/* shader */
		if ( !_pico_stricmp( p->token, "shader" ) ) {
			if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) {
				if ( shader != NULL ) {
					_pico_free( shader );
				}
				shader = _pico_clone_alloc( p->token );
			}
		}

		/* heightmap */
		else if ( !_pico_stricmp( p->token, "heightmap" ) ) {
			if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) {
				if ( heightmapFile != NULL ) {
					_pico_free( heightmapFile );
				}
				heightmapFile = _pico_clone_alloc( p->token );
			}
		}

		/* colormap */
		else if ( !_pico_stricmp( p->token, "colormap" ) ) {
			if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) {
				if ( colormapFile != NULL ) {
					_pico_free( colormapFile );
				}
				colormapFile = _pico_clone_alloc( p->token );
			}
		}

		/* scale */
		else if ( !_pico_stricmp( p->token, "scale" ) ) {
			_pico_parse_vec( p, scale );
		}

		/* skip unparsed rest of line and continue */
		_pico_parse_skip_rest( p );
	}

	/* ----------------------------------------------------------------- */

	/* load heightmap */
	heightmap = imageBuffer = NULL;
	_pico_load_file( heightmapFile, &imageBuffer, &imageBufSize );
	_terrain_load_tga_buffer( imageBuffer, &heightmap, &w, &h );
	_pico_free( heightmapFile );
	_pico_free_file( imageBuffer );

	if ( heightmap == NULL || w < 2 || h < 2 ) {
		_pico_printf( PICO_ERROR, "PicoTerrain model with invalid heightmap" );
		if ( shader != NULL ) {
			_pico_free( shader );
		}
		if ( colormapFile != NULL ) {
			_pico_free( colormapFile );
		}
		_pico_free_parser( p );
		return NULL;
	}

	/* set origin (bottom lowest corner of terrain mesh) */
	_pico_set_vec( origin, ( w / -2 ) * scale[ 0 ], ( h / -2 ) * scale[ 1 ], -128 * scale[ 2 ] );

	/* load colormap */
	colormap = imageBuffer = NULL;
	_pico_load_file( colormapFile, &imageBuffer, &imageBufSize );
	_terrain_load_tga_buffer( imageBuffer, &colormap, &cw, &ch );
	_pico_free( colormapFile );
	_pico_free_file( imageBuffer );

	if ( cw != w || ch != h ) {
		_pico_printf( PICO_WARNING, "PicoTerrain colormap/heightmap size mismatch" );
		_pico_free( colormap );
		colormap = NULL;
	}

	/* ----------------------------------------------------------------- */

	/* create new pico model */
	picoModel = PicoNewModel();
	if ( picoModel == NULL ) {
		_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
		return NULL;
	}

	/* do model setup */
	PicoSetModelFrameNum( picoModel, frameNum );
	PicoSetModelNumFrames( picoModel, 1 ); /* sea */
	PicoSetModelName( picoModel, fileName );
	PicoSetModelFileName( picoModel, fileName );

	/* allocate new pico surface */
	picoSurface = PicoNewSurface( picoModel );
	if ( picoSurface == NULL ) {
		_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
		PicoFreeModel( picoModel ); /* sea */
		return NULL;
	}

	/* terrain surfaces are triangle meshes */
	PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );

	/* set surface name */
	PicoSetSurfaceName( picoSurface, "picoterrain" );

	/* create new pico shader */
	picoShader = PicoNewShader( picoModel );
	if ( picoShader == NULL ) {
		_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
		PicoFreeModel( picoModel );
		_pico_free( shader );
		return NULL;
	}

	/* detox and set shader name */
	_pico_setfext( shader, "" );
	_pico_unixify( shader );
	PicoSetShaderName( picoShader, shader );
	_pico_free( shader );

	/* associate current surface with newly created shader */
	PicoSetSurfaceShader( picoSurface, picoShader );

	/* make bogus normal */
	_pico_set_vec( normal, 0.0f, 0.0f, 0.0f );

	/* create mesh */
	for ( j = 0; j < h; j++ )
	{
		for ( i = 0; i < w; i++ )
		{
			/* get pointers */
			v = i + ( j * w );
			heightPixel = heightmap + v * 4;
			colorPixel = colormap
						 ? colormap + v * 4
						 : NULL;

			/* set xyz */
			_pico_set_vec( xyz, origin[ 0 ] + scale[ 0 ] * i,
						   origin[ 1 ] + scale[ 1 ] * j,
						   origin[ 2 ] + scale[ 2 ] * heightPixel[ 0 ] );
			PicoSetSurfaceXYZ( picoSurface, v, xyz );

			/* set normal */
			PicoSetSurfaceNormal( picoSurface, v, normal );

			/* set st */
			st[ 0 ] = (float) i;
			st[ 1 ] = (float) j;
			PicoSetSurfaceST( picoSurface, 0, v, st );

			/* set color */
			if ( colorPixel != NULL ) {
				_pico_set_color( color, colorPixel[ 0 ], colorPixel[ 1 ], colorPixel[ 2 ], colorPixel[ 3 ] );
			}
			else{
				_pico_set_color( color, 255, 255, 255, 255 );
			}
			PicoSetSurfaceColor( picoSurface, 0, v, color );

			/* set triangles (zero alpha in heightmap suppresses this quad) */
			if ( i < ( w - 1 ) && j < ( h - 1 ) && heightPixel[ 3 ] >= 128 ) {
				/* set indexes */
				pw[ 0 ] = i + ( j * w );
				pw[ 1 ] = i + ( ( j + 1 ) * w );
				pw[ 2 ] = i + 1 + ( ( j + 1 ) * w );
				pw[ 3 ] = i + 1 + ( j * w );
				pw[ 4 ] = i + ( j * w );  /* same as pw[ 0 ] */

				/* set radix */
				r = ( i + j ) & 1;

				/* make first triangle */
				PicoSetSurfaceIndex( picoSurface, ( v * 6 + 0 ), (picoIndex_t) pw[ r + 0 ] );
				PicoSetSurfaceIndex( picoSurface, ( v * 6 + 1 ), (picoIndex_t) pw[ r + 1 ] );
				PicoSetSurfaceIndex( picoSurface, ( v * 6 + 2 ), (picoIndex_t) pw[ r + 2 ] );

				/* make second triangle */
				PicoSetSurfaceIndex( picoSurface, ( v * 6 + 3 ), (picoIndex_t) pw[ r + 0 ] );
				PicoSetSurfaceIndex( picoSurface, ( v * 6 + 4 ), (picoIndex_t) pw[ r + 2 ] );
				PicoSetSurfaceIndex( picoSurface, ( v * 6 + 5 ), (picoIndex_t) pw[ r + 3 ] );
			}
		}
	}

	/* free stuff */
	_pico_free_parser( p );
	_pico_free( heightmap );
	_pico_free( colormap );

	/* return the new pico model */
	return picoModel;
}
Exemplo n.º 5
0
static picoModel_t *_md2_load( PM_PARAMS_LOAD )
{
	int				i, j, dups, dup_index;
	index_LUT_t		*p_index_LUT, *p_index_LUT2, *p_index_LUT3;
	index_DUP_LUT_t	*p_index_LUT_DUPS;
	md2Triangle_t	*p_md2Triangle;

	char			skinname[ MD2_MAX_SKINNAME ];
 	md2_t			*md2;
 	md2St_t			*texCoord;
	md2Frame_t		*frame;
	md2Triangle_t	*triangle;
	md2XyzNormal_t	*vertex;

	picoByte_t      *bb, *bb0;
	picoModel_t		*picoModel;
	picoSurface_t	*picoSurface;
	picoShader_t	*picoShader;
	picoVec3_t		xyz, normal;
	picoVec2_t		st;
	picoColor_t		color;
	

	/* set as md2 */
	bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
	memcpy(bb, buffer, bufSize);
	md2	= (md2_t*) bb;

	/* check ident and version */
	if( *((const int*) md2->magic) != *((const int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION )
	{
		/* not an md2 file (todo: set error) */
		_pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );
		_pico_free(bb0);
		return NULL;
	}
	
	// swap md2
	md2->version = _pico_little_long( md2->version );

	md2->skinWidth = _pico_little_long( md2->skinWidth );
	md2->skinHeight = _pico_little_long( md2->skinHeight );
	md2->frameSize = _pico_little_long( md2->frameSize );

	md2->numSkins = _pico_little_long( md2->numSkins );
	md2->numXYZ = _pico_little_long( md2->numXYZ );
	md2->numST = _pico_little_long( md2->numST );
	md2->numTris = _pico_little_long( md2->numTris );
	md2->numGLCmds = _pico_little_long( md2->numGLCmds );
	md2->numFrames = _pico_little_long( md2->numFrames );

	md2->ofsSkins = _pico_little_long( md2->ofsSkins );
	md2->ofsST = _pico_little_long( md2->ofsST );
	md2->ofsTris = _pico_little_long( md2->ofsTris );
	md2->ofsFrames = _pico_little_long( md2->ofsFrames );
	md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );
	md2->ofsEnd = _pico_little_long( md2->ofsEnd );

	// do frame check
	if( md2->numFrames < 1 )
	{
		_pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
		_pico_free(bb0);
		return NULL;
	}
	
	if( frameNum < 0 || frameNum >= md2->numFrames )
	{
		_pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );
		_pico_free(bb0);
		return NULL;
	}

	// Setup Frame
	frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum));

	// swap frame scale and translation
	for( i = 0; i < 3; i++ )
	{
		frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );
		frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );
	}

	// swap triangles
	triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
	for( i = 0; i < md2->numTris; i++, triangle++ )
	{
		for( j = 0; j < 3; j++ )
		{
			triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
			triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
		}
	}

	// swap st coords
	texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
	for( i = 0; i < md2->numST; i++, texCoord++ )
	{
		texCoord->s = _pico_little_short( texCoord->s );
		texCoord->t = _pico_little_short( texCoord->t );
	}

	// set Skin Name
	strncpy(skinname, (const char *) (bb + md2->ofsSkins), MD2_MAX_SKINNAME );

	// Print out md2 values
	_pico_printf(PICO_VERBOSE,"Skins: %d  Verts: %d  STs: %d  Triangles: %d  Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname );

	// detox Skin name
	_pico_setfext( skinname, "" );
	_pico_unixify( skinname );

	/* create new pico model */
	picoModel = PicoNewModel();
	if( picoModel == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
		_pico_free(bb0);
		return NULL;
	}

	/* do model setup */
	PicoSetModelFrameNum( picoModel, frameNum );
	PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */
	PicoSetModelName( picoModel, fileName );
	PicoSetModelFileName( picoModel, fileName );

	// allocate new pico surface
	picoSurface = PicoNewSurface( picoModel );
	if( picoSurface == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
		PicoFreeModel( picoModel );
		_pico_free(bb0);
		return NULL;
	}


	PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
	PicoSetSurfaceName( picoSurface, frame->name );
	picoShader = PicoNewShader( picoModel );
	if( picoShader == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
		PicoFreeModel( picoModel );
		_pico_free(bb0);
		return NULL;
	}

	PicoSetShaderName( picoShader, skinname );

	// associate current surface with newly created shader
	PicoSetSurfaceShader( picoSurface, picoShader );

	// Init LUT for Verts
	p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ);
	for(i=0; i<md2->numXYZ; i++)
	{
		p_index_LUT[i].Vert = -1;
		p_index_LUT[i].ST = -1;
		p_index_LUT[i].next = NULL;
	}

	// Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
	dups = 0;
	for(i=0; i<md2->numTris; i++)
	{
		p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i));
		for(j=0; j<3; j++)
		{
			if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry
				p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j];

			else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry
				continue;

			else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) )  // Not equal to Main entry, and no LL entry
			{	// Add first entry of LL from Main
				p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
				if (p_index_LUT2 == NULL)
					_pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
				p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
				p_index_LUT2->Vert = dups;
				p_index_LUT2->ST = p_md2Triangle->index_st[j];
				p_index_LUT2->next = NULL;
				p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
				dups++;
			}
			else // Try to find in LL from Main Entry
			{
				p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next;
				while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
				{
					p_index_LUT3 = p_index_LUT2;
					p_index_LUT2 = p_index_LUT2->next;
				}
				p_index_LUT2 = p_index_LUT3;

				if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it
				{
					p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk
					continue;
				}

				if ( p_index_LUT2->next == NULL)  // Didn't find it. Add entry to LL.
				{
					// Add the Entry
					p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
					if (p_index_LUT3 == NULL)
						_pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
					p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
					p_index_LUT3->Vert = p_md2Triangle->index_xyz[j];
					p_index_LUT3->ST = p_md2Triangle->index_st[j];
					p_index_LUT3->next = NULL;
					p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
					dups++;
				}
			}
		}
	}

	// malloc and build array for Dup STs
	p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
	if (p_index_LUT_DUPS == NULL)
		_pico_printf( PICO_ERROR," Couldn't allocate memory!\n");

	dup_index = 0;
	for(i=0; i<md2->numXYZ; i++)
	{
		p_index_LUT2 = p_index_LUT[i].next;
		while (p_index_LUT2 != NULL)
		{
			p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
			p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
			dup_index++;
			p_index_LUT2 = p_index_LUT2->next;
		}
	}

	// Build Picomodel
	triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
	texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
	vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) );
	for( j = 0; j < md2->numTris; j++, triangle++ )
	{
		PicoSetSurfaceIndex( picoSurface, j*3   , triangle->index_xyz[0] );
		PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
		PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
	}

	for(i=0; i< md2->numXYZ; i++, vertex++)
	{
		/* set vertex origin */
		xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];
		xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];
		xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];
		PicoSetSurfaceXYZ( picoSurface, i , xyz );

		/* set normal */
		normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];
		normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];
		normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];
		PicoSetSurfaceNormal( picoSurface, i , normal );

		/* set st coords */
		st[ 0 ] =  ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth));
		st[ 1 ] =  (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight));
		PicoSetSurfaceST( picoSurface, 0, i , st );
	}

	if (dups)
	{
		for(i=0; i<dups; i++)
		{
			j = p_index_LUT_DUPS[i].OldVert;
			/* set vertex origin */
			xyz[ 0 ] = frame->verts[j].v[0] * frame->scale[0] + frame->translate[0];
			xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1];
			xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2];
			PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz );

			/* set normal */
			normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0];
			normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1];
			normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2];
			PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal );

			/* set st coords */
			st[ 0 ] =  ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth));
			st[ 1 ] =  (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight));
			PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st );
		}
	}

	/* set color */
	PicoSetSurfaceColor( picoSurface, 0, 0, color );

	// Free up malloc'ed LL entries
	for(i=0; i<md2->numXYZ; i++)
	{
		if(p_index_LUT[i].next != NULL)
		{
			p_index_LUT2 = p_index_LUT[i].next;
			do {
				p_index_LUT3 = p_index_LUT2->next;
				_pico_free(p_index_LUT2);
				p_index_LUT2 = p_index_LUT3;
				dups--;
			} while (p_index_LUT2 != NULL);
		}
	}

	if (dups)
		_pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");

	// Free malloc'ed LUTs
 	_pico_free(p_index_LUT);
	_pico_free(p_index_LUT_DUPS);

	/* return the new pico model */
	_pico_free(bb0);
	return picoModel;

}
Exemplo n.º 6
0
static picoModel_t *_md2_load( PM_PARAMS_LOAD )
{
	int				i, j;
	short			tot_numVerts;
	index_LUT_t		*p_index_LUT;
	md2Triangle_t	*p_md2Triangle;

	char			skinname[ MD2_MAX_SKINNAME ];
 	md2_t			*md2;
 	md2St_t			*texCoord;
	md2Frame_t		*frame;
	md2Triangle_t	*triangle;
	md2XyzNormal_t	*vertex;

	picoByte_t      *bb;
	picoModel_t		*picoModel;
	picoSurface_t	*picoSurface;
	picoShader_t	*picoShader;
	picoVec3_t		xyz, normal;
	picoVec2_t		st;
	picoColor_t		color;


	/* set as md2 */
	bb = (picoByte_t*) buffer;
	md2	= (md2_t*) buffer;

	/* check ident and version */
	if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION )
	{
		/* not an md2 file (todo: set error) */
		_pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );
		return NULL;
	}

	// swap md2
	md2->version = _pico_little_long( md2->version );

	md2->skinWidth = _pico_little_long( md2->skinWidth );
	md2->skinHeight = _pico_little_long( md2->skinHeight );
	md2->frameSize = _pico_little_long( md2->frameSize );

	md2->numSkins = _pico_little_long( md2->numSkins );
	md2->numXYZ = _pico_little_long( md2->numXYZ );
	md2->numST = _pico_little_long( md2->numST );
	md2->numTris = _pico_little_long( md2->numTris );
	md2->numGLCmds = _pico_little_long( md2->numGLCmds );
	md2->numFrames = _pico_little_long( md2->numFrames );

	md2->ofsSkins = _pico_little_long( md2->ofsSkins );
	md2->ofsST = _pico_little_long( md2->ofsST );
	md2->ofsTris = _pico_little_long( md2->ofsTris );
	md2->ofsFrames = _pico_little_long( md2->ofsFrames );
	md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );
	md2->ofsEnd = _pico_little_long( md2->ofsEnd );

	// do frame check
	if( md2->numFrames < 1 )
	{
		_pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
		return NULL;
	}

	if( frameNum < 0 || frameNum >= md2->numFrames )
	{
		_pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );
		return NULL;
	}

	// Setup Frame
	frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum));

	// swap frame scale and translation
	for( i = 0; i < 3; i++ )
	{
		frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );
		frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );
	}

	// swap triangles
	triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
	for( i = 0; i < md2->numTris; i++, triangle++ )
	{
		for( j = 0; j < 3; j++ )
		{
			triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
			triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
		}
	}

	// swap st coords
	texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
	for( i = 0; i < md2->numST; i++, texCoord++ )
	{
		texCoord->s = _pico_little_short( texCoord->s );
		texCoord->t = _pico_little_short( texCoord->t );
	}

	// Print out md2 values
	_pico_printf(PICO_VERBOSE,"Skins: %d  Verts: %d  STs: %d  Triangles: %d  Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname );

	/* create new pico model */
	picoModel = PicoNewModel();
	if( picoModel == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
		return NULL;
	}

	/* do model setup */
	PicoSetModelFrameNum( picoModel, frameNum );
	PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */
	PicoSetModelName( picoModel, fileName );
	PicoSetModelFileName( picoModel, fileName );

	for (i = 0; i < md2->numSkins; i++) {
		char *offsetSkin = (char*) (bb + md2->ofsSkins) + i * MD2_MAX_SKINNAME;
		/* set Skin Name */
		strncpy(skinname, offsetSkin, MD2_MAX_SKINNAME);

		/* detox Skin name */
		if (skinname[0] == '.') {/* special case ufoai skinpath */
			char path[MD2_MAX_SKINNAME];
			char skinnameRelative[MD2_MAX_SKINNAME];
			strncpy(path, fileName, MD2_MAX_SKINNAME);
			strncpy(skinnameRelative, skinname, MD2_MAX_SKINNAME);
			_pico_unixify(path);
			for (j = MD2_MAX_SKINNAME; j--;) {/* skip filename */
				if (path[j] == '/')
					break;
				path[j] = '\0';
			}
			snprintf(skinname, MD2_MAX_SKINNAME, "%s%s", path, &skinnameRelative[1]);
		}
		_pico_setfext(skinname, "");

		picoShader = PicoNewShader(picoModel);
		if (picoShader == NULL) {
			_pico_printf(PICO_ERROR, "Unable to allocate a new model shader");
			PicoFreeModel(picoModel);
			return NULL;
		}

		PicoSetShaderName(picoShader, skinname);
	}

	// allocate new pico surface
	picoSurface = PicoNewSurface( picoModel );
	if( picoSurface == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
		PicoFreeModel( picoModel );
		return NULL;
	}


	PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
	PicoSetSurfaceName( picoSurface, frame->name );
	picoShader = PicoNewShader( picoModel );
	if( picoShader == NULL )
	{
		_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
		PicoFreeModel( picoModel );
		return NULL;
	}

	PicoSetShaderName( picoShader, skinname );

	// associate current surface with newly created shader
	PicoSetSurfaceShader( picoSurface, picoShader );

	// Init LUT for Verts
	p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ);
	for(i=0; i<md2->numXYZ; i++)
	{
		p_index_LUT[i].Vert = -1;
		p_index_LUT[i].ST = -1;
	}

	/* Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. */
	tot_numVerts = md2->numXYZ;
	for (i = 0; i < md2->numTris; i++) {
		p_md2Triangle = (md2Triangle_t *) (bb + md2->ofsTris + (sizeof(md2Triangle_t) * i));
		for (j = 0; j < 3; j++) {
			if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) /* No Main Entry */
				p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j];
		}
	}

	/* Build Picomodel */
	triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris));
	for (j = 0; j < md2->numTris; j++, triangle++) {
		PicoSetSurfaceIndex(picoSurface, j * 3, triangle->index_xyz[0]);
		PicoSetSurfaceIndex(picoSurface, j * 3 + 1, triangle->index_xyz[1]);
		PicoSetSurfaceIndex(picoSurface, j * 3 + 2, triangle->index_xyz[2]);
	}

	_pico_set_color(color, 255, 255, 255, 255);

	texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST));
	vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts));
	for (i = 0; i < md2->numXYZ; i++, vertex++) {
		/* set vertex origin */
		xyz[0] = vertex->v[0] * frame->scale[0] + frame->translate[0];
		xyz[1] = vertex->v[1] * frame->scale[1] + frame->translate[1];
		xyz[2] = vertex->v[2] * frame->scale[2] + frame->translate[2];
		PicoSetSurfaceXYZ(picoSurface, i, xyz);

		/* set normal */
		normal[0] = md2_normals[vertex->lightnormalindex][0];
		normal[1] = md2_normals[vertex->lightnormalindex][1];
		normal[2] = md2_normals[vertex->lightnormalindex][2];
		PicoSetSurfaceNormal(picoSurface, i, normal);

		/* set st coords */
		st[0] = (float) texCoord[p_index_LUT[i].ST].s / (float) md2->skinWidth;
		st[1] = (float) texCoord[p_index_LUT[i].ST].t / (float) md2->skinHeight;
		PicoSetSurfaceST(picoSurface, 0, i, st);

		/* set color */
		PicoSetSurfaceColor(picoSurface, 0, i, color);
	}

	/* Free malloc'ed LUTs */
	_pico_free(p_index_LUT);

	/* return the new pico model */
	return picoModel;
}
Exemplo n.º 7
0
static int GetMeshShader (T3dsLoaderPers *pers)
{
    char shaderName[255] = { 0 };
    picoShader_t  *shader;
    int  numSharedVerts;
    int  setShaderName = 0;
    int  i;
    
    /* the shader is either the color or the texture map of the */
    /* object. it can also hold other information like the brightness, */
    /* shine, etc. stuff we don't really care about. we just want the */
    /* color, or the texture map file name really */

    /* get in the shader name */
    if (!GetASCIIZ(pers,shaderName,sizeof(shaderName)))
        return 0;
    
    /* ydnar: trim to first whitespace */
    _pico_first_token( shaderName );
    
    /* now that we have the shader name we need to go through all of */
    /* the shaders and check the name against each shader. when we */
    /* find a shader in our shader list that matches this name we */
    /* just read in, then we assign the shader's id of the object to */
    /* that shader */

    /* get shader id for shader name */
    shader = PicoFindShader( pers->model, shaderName, 1 );

    /* we've found a matching shader */
    if ((shader != NULL) && pers->surface)
    {
        char  mapName[1024+1];
        char *mapNamePtr;
        memset( mapName,0,sizeof(mapName) );

        /* get ptr to shader's map name */
        mapNamePtr = PicoGetShaderMapName( shader );

        /* we have a valid map name ptr */
        if (mapNamePtr != NULL)
        {
            char  temp[128];
            const char *name;

            /* copy map name to local buffer */
            strcpy( mapName,mapNamePtr );

            /* extract file name */
            name = _pico_nopath( mapName );
            strncpy( temp, name, sizeof(temp) );

            /* remove file extension */
            /* name = _pico_setfext( name,"" ); */

            /* assign default name if no name available */
            if (strlen(temp) < 1)
                strcpy(temp,pers->basename);

            /* build shader name */
            _pico_strlwr( temp ); /* gaynux update -sea */
            sprintf( mapName,"models/mapobjects/%s/%s",pers->basename,temp );

            /* set shader name */
            /* PicoSetShaderName( shader,mapName ); */    /* ydnar: this will screw up the named shader */

            /* set surface's shader index */
            PicoSetSurfaceShader( pers->surface, shader );

            setShaderName = 1;
        }
    }
    /* we didn't set a shader name; throw out warning */
    if (!setShaderName)
    {
        _pico_printf( PICO_WARNING,"3DS mesh is missing shader name");
    }
    /* we don't process the list of shared vertices here; there is a */
    /* short int that gives the number of faces of the mesh concerned */
    /* by this shader, then there is the list itself of these faces. */
    /* 0000 means the first face of the (4120) face list */

    /* get number of shared verts */
    numSharedVerts = GetWord(pers);

#ifdef DEBUG_PM_3DS
    printf("GetMeshShader: uses shader '%s' (nsv %d)\n",shaderName,numSharedVerts);
#endif
    /* skip list of shared verts */
    for (i=0; i<numSharedVerts; i++)
    {
        GetWord(pers);
    }
    /* success (no errors occured) */
    return 1;
}
Exemplo n.º 8
0
/**
 * @brief loads a wavefront obj model file.
 */
static picoModel_t *_obj_load (PM_PARAMS_LOAD)
{
	TObjVertexData *vertexData = NULL;
	picoModel_t *model;
	picoSurface_t *curSurface = NULL;
	picoParser_t *p;
	int allocated;
	int entries;
	int numVerts = 0;
	int numNormals = 0;
	int numUVs = 0;
	int curVertex = 0;
	int curFace = 0;
	picoShader_t *shader;

	/* helper */
#define _obj_error_return(m) \
	{ \
		_pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine); \
		_pico_free_parser( p ); \
		FreeObjVertexData( vertexData ); \
		PicoFreeModel( model ); \
		return NULL; \
	}
	/* alllocate a new pico parser */
	p = _pico_new_parser((picoByte_t *) buffer, bufSize);
	if (p == NULL)
		return NULL;

	/* create a new pico model */
	model = PicoNewModel();
	if (model == NULL) {
		_pico_free_parser(p);
		return NULL;
	}
	/* do model setup */
	PicoSetModelFrameNum(model, frameNum);
	PicoSetModelName(model, fileName);
	PicoSetModelFileName(model, fileName);

	/* try loading the materials; we don't handle the result */
	shader = _obj_default_shader(model);
#if 0
	shader = _obj_mtl_load(model);
#endif

	/* parse obj line by line */
	while (1) {
		/* get first token on line */
		if (_pico_parse_first(p) == NULL)
			break;

		/* skip empty lines */
		if (p->token == NULL || !strlen(p->token))
			continue;

		/* skip comment lines */
		if (p->token[0] == '#') {
			_pico_parse_skip_rest(p);
			continue;
		}
		/* vertex */
		if (!_pico_stricmp(p->token, "v")) {
			TObjVertexData *data;
			picoVec3_t v;

			vertexData = SizeObjVertexData(vertexData, numVerts + 1, &entries, &allocated);
			if (vertexData == NULL)
				_obj_error_return("Realloc of vertex data failed (1)");

			data = &vertexData[numVerts++];

			/* get and copy vertex */
			if (!_pico_parse_vec(p, v))
				_obj_error_return("Vertex parse error");

			_pico_copy_vec(v, data->v);

#ifdef DEBUG_PM_OBJ_EX
			printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]);
#endif
		}
		/* uv coord */
		else if (!_pico_stricmp(p->token, "vt")) {
			TObjVertexData *data;
			picoVec2_t coord;

			vertexData = SizeObjVertexData(vertexData, numUVs + 1, &entries, &allocated);
			if (vertexData == NULL)
				_obj_error_return("Realloc of vertex data failed (2)");

			data = &vertexData[numUVs++];

			/* get and copy tex coord */
			if (!_pico_parse_vec2(p, coord))
				_obj_error_return("UV coord parse error");

			_pico_copy_vec2(coord, data->vt);

#ifdef DEBUG_PM_OBJ_EX
			printf("TexCoord: u: %f v: %f\n",coord[0],coord[1]);
#endif
		}
		/* vertex normal */
		else if (!_pico_stricmp(p->token, "vn")) {
			TObjVertexData *data;
			picoVec3_t n;

			vertexData = SizeObjVertexData(vertexData, numNormals + 1, &entries, &allocated);
			if (vertexData == NULL)
				_obj_error_return("Realloc of vertex data failed (3)");

			data = &vertexData[numNormals++];

			/* get and copy vertex normal */
			if (!_pico_parse_vec(p, n))
				_obj_error_return("Vertex normal parse error");

			_pico_copy_vec(n, data->vn);

#ifdef DEBUG_PM_OBJ_EX
			printf("Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2]);
#endif
		}
		/* new group (for us this means a new surface) */
		else if (!_pico_stricmp(p->token, "g")) {
			picoSurface_t *newSurface;
			char *groupName;

			/* get first group name (ignore 2nd,3rd,etc.) */
			groupName = _pico_parse(p, 0);
			if (groupName == NULL || !strlen(groupName)) {
				/* some obj exporters feel like they don't need to */
				/* supply a group name. so we gotta handle it here */
#if 1
				strcpy(p->token, "default");
				groupName = p->token;
#else
				_obj_error_return("Invalid or missing group name");
#endif
			}
			/* allocate a pico surface */
			newSurface = PicoNewSurface(model);
			if (newSurface == NULL)
				_obj_error_return("Error allocating surface");

			/* reset face index for surface */
			curFace = 0;

			/* set ptr to current surface */
			curSurface = newSurface;

			/* we use triangle meshes */
			PicoSetSurfaceType(newSurface, PICO_TRIANGLES);

			/* set surface name */
			PicoSetSurfaceName(newSurface, groupName);

			/* associate current surface with newly created shader */
			PicoSetSurfaceShader(newSurface, shader);

#ifdef DEBUG_PM_OBJ_EX
			printf("Group: '%s'\n",groupName);
#endif
		}
		/* face (oh jesus, hopefully this will do the job right ;) */
		else if (!_pico_stricmp(p->token, "f")) {
			/* okay, this is a mess. some 3d apps seem to try being unique, */
			/* hello cinema4d & 3d exploration, feel good today?, and save */
			/* this crap in tons of different formats. gah, those screwed */
			/* coders. tho the wavefront obj standard defines exactly two */
			/* ways of storing face information. so, i really won't support */
			/* such stupid extravaganza here! */

			picoVec3_t verts[4];
			picoVec3_t normals[4];
			picoVec2_t coords[4];

			int iv[4], has_v;
			int ivt[4], has_vt = 0;
			int ivn[4], has_vn = 0;
			int have_quad = 0;
			int slashcount;
			int doubleslash;
			int i;

			/* group defs *must* come before faces */
			if (curSurface == NULL)
				_obj_error_return("No group defined for faces");

#ifdef DEBUG_PM_OBJ_EX
			printf("Face: ");
#endif
			/* read vertex/uv/normal indices for the first three face */
			/* vertices (cause we only support triangles) into 'i*[]' */
			/* store the actual vertex/uv/normal data in three arrays */
			/* called 'verts','coords' and 'normals'. */
			for (i = 0; i < 4; i++) {
				char *str;

				/* get next vertex index string (different */
				/* formats are handled below) */
				str = _pico_parse(p, 0);
				if (str == NULL) {
					/* just break for quads */
					if (i == 3)
						break;

					/* error otherwise */
					_obj_error_return("Face parse error");
				}
				/* if this is the fourth index string we're */
				/* parsing we assume that we have a quad */
				if (i == 3)
					have_quad = 1;

				/* get slash count once */
				if (i == 0) {
					slashcount = _pico_strchcount(str, '/');
					doubleslash = strstr(str, "//") != NULL;
				}
				/* handle format 'v//vn' */
				if (doubleslash && (slashcount == 2)) {
					has_v = has_vn = 1;
					sscanf(str, "%d//%d", &iv[i], &ivn[i]);
				}
				/* handle format 'v/vt/vn' */
				else if (!doubleslash && (slashcount == 2)) {
					has_v = has_vt = has_vn = 1;
					sscanf(str, "%d/%d/%d", &iv[i], &ivt[i], &ivn[i]);
				}
				/* handle format 'v/vt' (non-standard fuckage) */
				else if (!doubleslash && (slashcount == 1)) {
					has_v = has_vt = 1;
					sscanf(str, "%d/%d", &iv[i], &ivt[i]);
				}
				/* else assume face format 'v' */
				/* (must have been invented by some bored granny) */
				else {
					/* get single vertex index */
					has_v = 1;
					iv[i] = atoi(str);

					/* either invalid face format or out of range */
					if (iv[i] == 0)
						_obj_error_return("Invalid face format");
				}
				/* fix useless back references */
				/* todo: check if this works as it is supposed to */

				/* assign new indices */
				if (iv[i] < 0)
					iv[i] = (numVerts - iv[i]);
				if (ivt[i] < 0)
					ivt[i] = (numUVs - ivt[i]);
				if (ivn[i] < 0)
					ivn[i] = (numNormals - ivn[i]);

				/* validate indices */
				/* - commented out. index range checks will trigger
				 if (iv [ i ] < 1) iv [ i ] = 1;
				 if (ivt[ i ] < 1) ivt[ i ] = 1;
				 if (ivn[ i ] < 1) ivn[ i ] = 1;
				 */
				/* set vertex origin */
				if (has_v) {
					/* check vertex index range */
					if (iv[i] < 1 || iv[i] > numVerts)
						_obj_error_return("Vertex index out of range");

					/* get vertex data */
					verts[i][0] = vertexData[iv[i] - 1].v[0];
					verts[i][1] = vertexData[iv[i] - 1].v[1];
					verts[i][2] = vertexData[iv[i] - 1].v[2];
				}
				/* set vertex normal */
				if (has_vn) {
					/* check normal index range */
					if (ivn[i] < 1 || ivn[i] > numNormals)
						_obj_error_return("Normal index out of range");

					/* get normal data */
					normals[i][0] = vertexData[ivn[i] - 1].vn[0];
					normals[i][1] = vertexData[ivn[i] - 1].vn[1];
					normals[i][2] = vertexData[ivn[i] - 1].vn[2];
				}
				/* set texture coordinate */
				if (has_vt) {
					/* check uv index range */
					if (ivt[i] < 1 || ivt[i] > numUVs)
						_obj_error_return("UV coord index out of range");

					/* get uv coord data */
					coords[i][0] = vertexData[ivt[i] - 1].vt[0];
					coords[i][1] = vertexData[ivt[i] - 1].vt[1];
					coords[i][1] = -coords[i][1];
				}
#ifdef DEBUG_PM_OBJ_EX
				printf("(%4d",iv[ i ]);
				if (has_vt) printf(" %4d",ivt[ i ]);
				if (has_vn) printf(" %4d",ivn[ i ]);
				printf(") ");
#endif
			}
#ifdef DEBUG_PM_OBJ_EX
			printf("\n");
#endif
			/* now that we have extracted all the indices and have
			 * read the actual data we need to assign all the crap
			 * to our current pico surface */
			if (has_v) {
				int max = 3;
				if (have_quad)
					max = 4;

				/* assign all surface information */
				for (i = 0; i < max; i++) {
					PicoSetSurfaceXYZ(curSurface, (curVertex + i), verts[i]);
					PicoSetSurfaceST(curSurface, 0, (curVertex + i), coords[i]);
					PicoSetSurfaceNormal(curSurface, (curVertex + i), normals[i]);
				}
				/* add our triangle (A B C) */
				PicoSetSurfaceIndex(curSurface, (curFace * 3 + 2), (picoIndex_t) (curVertex + 0));
				PicoSetSurfaceIndex(curSurface, (curFace * 3 + 1), (picoIndex_t) (curVertex + 1));
				PicoSetSurfaceIndex(curSurface, (curFace * 3 + 0), (picoIndex_t) (curVertex + 2));
				curFace++;

				/* if we don't have a simple triangle, but a quad... */
				if (have_quad) {
					/* we have to add another triangle (2nd half of quad which is A C D) */
					PicoSetSurfaceIndex(curSurface, (curFace * 3 + 2), (picoIndex_t) (curVertex + 0));
					PicoSetSurfaceIndex(curSurface, (curFace * 3 + 1), (picoIndex_t) (curVertex + 2));
					PicoSetSurfaceIndex(curSurface, (curFace * 3 + 0), (picoIndex_t) (curVertex + 3));
					curFace++;
				}

				/* associate current surface with newly created shader */
				PicoSetSurfaceShader(curSurface, shader);

				/* increase vertex count */
				curVertex += max;
			}
		}
		/* skip unparsed rest of line and continue */
		_pico_parse_skip_rest(p);
	}
	/* free memory used by temporary vertexdata */
	FreeObjVertexData(vertexData);

	/* return allocated pico model */
	return model;
}
Exemplo n.º 9
0
/* _obj_load:
 *  loads a wavefront obj model file.
 */
static picoModel_t *_obj_load( PM_PARAMS_LOAD ){
	TObjVertexData *vertexData  = NULL;
	picoModel_t    *model;
	picoSurface_t  *curSurface  = NULL;
	picoParser_t   *p;
	int allocated = 0;
	int entries;
	int numVerts    = 0;
	int numNormals  = 0;
	int numUVs      = 0;
	int curVertex   = 0;
	int curFace     = 0;

	int autoGroupNumber = 0;
	char autoGroupNameBuf[64];

#define AUTO_GROUPNAME( namebuf ) \
	sprintf( namebuf, "__autogroup_%d", autoGroupNumber++ )
#define NEW_SURFACE( name )	\
	{ \
		picoSurface_t *newSurface; \
		/* allocate a pico surface */ \
		newSurface = PicoNewSurface( model ); \
		if ( newSurface == NULL ) {	\
			_obj_error_return( "Error allocating surface" ); } \
		/* reset face index for surface */ \
		curFace = 0; \
		curVertex = 0; \
		/* if we can, assign the previous shader to this surface */	\
		if ( curSurface ) {	\
			PicoSetSurfaceShader( newSurface, curSurface->shader ); } \
		/* set ptr to current surface */ \
		curSurface = newSurface; \
		/* we use triangle meshes */ \
		PicoSetSurfaceType( newSurface,PICO_TRIANGLES ); \
		/* set surface name */ \
		PicoSetSurfaceName( newSurface,name ); \
	}

	/* helper */
#define _obj_error_return( m ) \
	{ \
		_pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine ); \
		_pico_free_parser( p );	\
		FreeObjVertexData( vertexData ); \
		PicoFreeModel( model );	\
		return NULL; \
	}
	/* allocate a new pico parser */
	p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
	if ( p == NULL ) {
		return NULL;
	}

	/* create a new pico model */
	model = PicoNewModel();
	if ( model == NULL ) {
		_pico_free_parser( p );
		return NULL;
	}
	/* do model setup */
	PicoSetModelFrameNum( model,frameNum );
	PicoSetModelName( model,fileName );
	PicoSetModelFileName( model,fileName );

	/* try loading the materials */
	_obj_mtl_load( model );

	/* parse obj line by line */
	while ( 1 )
	{
		/* get first token on line */
		if ( _pico_parse_first( p ) == NULL ) {
			break;
		}

		/* skip empty lines */
		if ( p->token == NULL || !strlen( p->token ) ) {
			continue;
		}

		/* skip comment lines */
		if ( p->token[0] == '#' ) {
			_pico_parse_skip_rest( p );
			continue;
		}
		/* vertex */
		if ( !_pico_stricmp( p->token,"v" ) ) {
			TObjVertexData *data;
			picoVec3_t v;

			vertexData = SizeObjVertexData( vertexData,numVerts + 1,&entries,&allocated );
			if ( vertexData == NULL ) {
				_obj_error_return( "Realloc of vertex data failed (1)" );
			}

			data = &vertexData[ numVerts++ ];

			/* get and copy vertex */
			if ( !_pico_parse_vec( p,v ) ) {
				_obj_error_return( "Vertex parse error" );
			}

			_pico_copy_vec( v,data->v );

#ifdef DEBUG_PM_OBJ_EX
			printf( "Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2] );
#endif
		}
		/* uv coord */
		else if ( !_pico_stricmp( p->token,"vt" ) ) {
			TObjVertexData *data;
			picoVec2_t coord;

			vertexData = SizeObjVertexData( vertexData,numUVs + 1,&entries,&allocated );
			if ( vertexData == NULL ) {
				_obj_error_return( "Realloc of vertex data failed (2)" );
			}

			data = &vertexData[ numUVs++ ];

			/* get and copy tex coord */
			if ( !_pico_parse_vec2( p,coord ) ) {
				_obj_error_return( "UV coord parse error" );
			}

			_pico_copy_vec2( coord,data->vt );

#ifdef DEBUG_PM_OBJ_EX
			printf( "TexCoord: u: %f v: %f\n",coord[0],coord[1] );
#endif
		}
		/* vertex normal */
		else if ( !_pico_stricmp( p->token,"vn" ) ) {
			TObjVertexData *data;
			picoVec3_t n;

			vertexData = SizeObjVertexData( vertexData,numNormals + 1,&entries,&allocated );
			if ( vertexData == NULL ) {
				_obj_error_return( "Realloc of vertex data failed (3)" );
			}

			data = &vertexData[ numNormals++ ];

			/* get and copy vertex normal */
			if ( !_pico_parse_vec( p,n ) ) {
				_obj_error_return( "Vertex normal parse error" );
			}

			_pico_copy_vec( n,data->vn );

#ifdef DEBUG_PM_OBJ_EX
			printf( "Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2] );
#endif
		}
		/* new group (for us this means a new surface) */
		else if ( !_pico_stricmp( p->token,"g" ) ) {
			char *groupName;

			/* get first group name (ignore 2nd,3rd,etc.) */
			groupName = _pico_parse( p,0 );
			if ( groupName == NULL || !strlen( groupName ) ) {
				/* some obj exporters feel like they don't need to */
				/* supply a group name. so we gotta handle it here */
#if 1
				strcpy( p->token,"default" );
				groupName = p->token;
#else
				_obj_error_return( "Invalid or missing group name" );
#endif
			}

			if ( curFace == 0 && curSurface != NULL ) {
				PicoSetSurfaceName( curSurface,groupName );
			}
			else
			{
				NEW_SURFACE( groupName );
			}

#ifdef DEBUG_PM_OBJ_EX
			printf( "Group: '%s'\n",groupName );
#endif
		}
		/* face (oh jesus, hopefully this will do the job right ;) */
		else if ( !_pico_stricmp( p->token,"f" ) ) {
			/* okay, this is a mess. some 3d apps seem to try being unique, */
			/* hello cinema4d & 3d exploration, feel good today?, and save */
			/* this crap in tons of different formats. gah, those screwed */
			/* coders. tho the wavefront obj standard defines exactly two */
			/* ways of storing face information. so, i really won't support */
			/* such stupid extravaganza here! */
			const int numPointsMax = 128;
			picoVec3_t verts  [ numPointsMax ];
			picoVec3_t normals[ numPointsMax ];
			picoVec2_t coords [ numPointsMax ];

			int iv [ numPointsMax ], has_v;
			int ivt[ numPointsMax ], has_vt = 0;
			int ivn[ numPointsMax ], has_vn = 0;
			int slashcount = 0;
			int doubleslash = 0;
			int i;

			if ( curSurface == NULL ) {
				_pico_printf( PICO_WARNING,"No group defined for faces, so creating an autoSurface in OBJ, line %d.",p->curLine );
				AUTO_GROUPNAME( autoGroupNameBuf );
				NEW_SURFACE( autoGroupNameBuf );
			}

			/* group defs *must* come before faces */
			if ( curSurface == NULL ) {
				_obj_error_return( "No group defined for faces" );
			}

#ifdef DEBUG_PM_OBJ_EX
			printf( "Face: " );
#endif
			/* read vertex/uv/normal indices for the first three face */
			/* vertices (cause we only support triangles) into 'i*[]' */
			/* store the actual vertex/uv/normal data in three arrays */
			/* called 'verts','coords' and 'normals'. */
			for ( i = 0; i < numPointsMax; i++ )
			{
				char *str;

				/* get next vertex index string (different */
				/* formats are handled below) */
				str = _pico_parse( p,0 );
				if ( str == NULL ) {
					/* got nuff points */
					if ( i >= 3 ) {
						break;
					}

					/* error otherwise */
					_obj_error_return( "Face parse error" );
				}

				/* get slash count once */
				if ( i == 0 ) {
					slashcount  = _pico_strchcount( str,'/' );
					doubleslash =  strstr( str,"//" ) != NULL;
				}
				/* handle format 'v//vn' */
				if ( doubleslash && ( slashcount == 2 ) ) {
					has_v = has_vn = 1;
					sscanf( str,"%d//%d",&iv[ i ],&ivn[ i ] );
				}
				/* handle format 'v/vt/vn' */
				else if ( !doubleslash && ( slashcount == 2 ) ) {
					has_v = has_vt = has_vn = 1;
					sscanf( str,"%d/%d/%d",&iv[ i ],&ivt[ i ],&ivn[ i ] );
				}
				/* handle format 'v/vt' (non-standard fuckage) */
				else if ( !doubleslash && ( slashcount == 1 ) ) {
					has_v = has_vt = 1;
					sscanf( str,"%d/%d",&iv[ i ],&ivt[ i ] );
				}
				/* else assume face format 'v' */
				/* (must have been invented by some bored granny) */
				else {
					/* get single vertex index */
					has_v = 1;
					iv[ i ] = atoi( str );

					/* either invalid face format or out of range */
					if ( iv[ i ] == 0 ) {
						_obj_error_return( "Invalid face format" );
					}
				}
				/* fix useless back references */
				/* assign new indices */
				if ( iv [ i ] < 0 ) {
					iv [ i ] = ( numVerts   + iv [ i ] + 1 );
				}
				if ( ivt[ i ] < 0 ) {
					ivt[ i ] = ( numUVs     + ivt[ i ] + 1 );
				}
				if ( ivn[ i ] < 0 ) {
					ivn[ i ] = ( numNormals + ivn[ i ] + 1 );
				}

				/* validate indices */
				/* - commented out. index range checks will trigger
				   if (iv [ i ] < 1) iv [ i ] = 1;
				   if (ivt[ i ] < 1) ivt[ i ] = 1;
				   if (ivn[ i ] < 1) ivn[ i ] = 1;
				 */
				/* set vertex origin */
				if ( has_v ) {
					/* check vertex index range */
					if ( iv[ i ] < 1 || iv[ i ] > numVerts ) {
						_obj_error_return( "Vertex index out of range" );
					}

					/* get vertex data */
					verts[ i ][ 0 ] =  vertexData[ iv[ i ] - 1 ].v[ 0 ];
					verts[ i ][ 1 ] = -vertexData[ iv[ i ] - 1 ].v[ 2 ];
					verts[ i ][ 2 ] =  vertexData[ iv[ i ] - 1 ].v[ 1 ];
				}
				/* set vertex normal */
				if ( has_vn ) {
					/* check normal index range */
					if ( ivn[ i ] < 1 || ivn[ i ] > numNormals ) {
						_obj_error_return( "Normal index out of range" );
					}

					/* get normal data */
					normals[ i ][ 0 ] =  vertexData[ ivn[ i ] - 1 ].vn[ 0 ];
					normals[ i ][ 1 ] = -vertexData[ ivn[ i ] - 1 ].vn[ 2 ];
					normals[ i ][ 2 ] =  vertexData[ ivn[ i ] - 1 ].vn[ 1 ];
				}
				/* set texture coordinate */
				if ( has_vt ) {
					/* check uv index range */
					if ( ivt[ i ] < 1 || ivt[ i ] > numUVs ) {
						_obj_error_return( "UV coord index out of range" );
					}

					/* get uv coord data */
					coords[ i ][ 0 ] =  vertexData[ ivt[ i ] - 1 ].vt[ 0 ];
					coords[ i ][ 1 ] = -vertexData[ ivt[ i ] - 1 ].vt[ 1 ];
				}
#ifdef DEBUG_PM_OBJ_EX
				printf( "(%4d",iv[ i ] );
				if ( has_vt ) {
					printf( " %4d",ivt[ i ] );
				}
				if ( has_vn ) {
					printf( " %4d",ivn[ i ] );
				}
				printf( ") " );
#endif
			}
#ifdef DEBUG_PM_OBJ_EX
			printf( "\n" );
#endif
			/* now that we have extracted all the indices and have */
			/* read the actual data we need to assign all the crap */
			/* to our current pico surface */
			if ( has_v ) {
				const int numPoints = i;

				/* assign all surface information */
				for ( i = 0; i < numPoints; i++ )
				{
					/*if( has_v  )*/ PicoSetSurfaceXYZ( curSurface,  ( curVertex + i ), verts  [ i ] );
					/*if( has_vt )*/ PicoSetSurfaceST( curSurface, 0, ( curVertex + i ), coords [ i ] );
					/*if( has_vn )*/ PicoSetSurfaceNormal( curSurface,  ( curVertex + i ), normals[ i ] );
					if( curSurface && curSurface->shader )
						PicoSetSurfaceColor( curSurface, 0, ( curVertex + i ), curSurface->shader->diffuseColor );
				}
				/* add triangles */
				for ( i = 1; i < numPoints - 1; ++i )
				{
					PicoSetSurfaceIndex( curSurface,( curFace * 3 + 2 ),(picoIndex_t)( curVertex + 0 ) );
					PicoSetSurfaceIndex( curSurface,( curFace * 3 + 1 ),(picoIndex_t)( curVertex + i ) );
					PicoSetSurfaceIndex( curSurface,( curFace * 3 + 0 ),(picoIndex_t)( curVertex + i + 1 ) );
					curFace++;
				}
				/* increase vertex count */
				curVertex += numPoints;
			}
		}
		else if ( !_pico_stricmp( p->token,"usemtl" ) ) {
			picoShader_t *shader;
			char *name;

			/* get material name */
			name = _pico_parse( p,0 );

			if ( curFace != 0 || curSurface == NULL ) {
				_pico_printf( PICO_WARNING,"No group defined for usemtl, so creating an autoSurface in OBJ, line %d.",p->curLine );
				AUTO_GROUPNAME( autoGroupNameBuf );
				NEW_SURFACE( autoGroupNameBuf );
			}

			/* validate material name */
			if ( name == NULL || !strlen( name ) ) {
				_pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine );
			}
			else
			{
				shader = PicoFindShader( model, name, 1 );
				if ( shader == NULL ) {
					_pico_printf( PICO_WARNING, "Undefined material name \"%s\" in OBJ, line %d. Making a default shader.", name, p->curLine );

					/* create a new pico shader */
					shader = PicoNewShader( model );
					if ( shader != NULL ) {
						PicoSetShaderName( shader,name );
						PicoSetShaderMapName( shader,name );
						PicoSetSurfaceShader( curSurface, shader );
					}
				}
				else
				{
					PicoSetSurfaceShader( curSurface, shader );
				}
			}
		}
		/* skip unparsed rest of line and continue */
		_pico_parse_skip_rest( p );
	}

	/* free memory used by temporary vertexdata */
	FreeObjVertexData( vertexData );

	/* return allocated pico model */
	return model;
//	return NULL;
}
Exemplo n.º 10
0
/**
 * @brief A nice way to add individual triangles to the model.
 * Chooses an appropriate surface based on the shader, or adds a new surface if necessary
 */
void PicoAddTriangleToModel (picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st,
		int numColors, picoColor_t **colors, picoShader_t* shader, picoIndex_t* smoothingGroup)
{
	int i, j;
	int vertDataIndex;
	picoSurface_t* workSurface = NULL;

	/* see if a surface already has the shader */
	for (i = 0; i < model->numSurfaces; i++) {
		workSurface = model->surface[i];
		if (workSurface->shader == shader) {
			break;
		}
	}

	/* no surface uses this shader yet, so create a new surface */
	if (!workSurface || i >= model->numSurfaces) {
		/* create a new surface in the model for the unique shader */
		workSurface = PicoNewSurface(model);
		if (!workSurface) {
			_pico_printf(PICO_ERROR, "Could not allocate a new surface!\n");
			return;
		}

		/* do surface setup */
		PicoSetSurfaceType(workSurface, PICO_TRIANGLES);
		PicoSetSurfaceName(workSurface, shader->name);
		PicoSetSurfaceShader(workSurface, shader);
	}

	/* add the triangle data to the surface */
	for (i = 0; i < 3; i++) {
		/* get the next free spot in the index array */
		int newVertIndex = PicoGetSurfaceNumIndexes(workSurface);

		/* get the index of the vertex that we're going to store at newVertIndex */
		vertDataIndex = PicoFindSurfaceVertexNum(workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors,
				colors[i], smoothingGroup[i]);

		/* the vertex wasn't found, so create a new vertex in the pool from the data we have */
		if (vertDataIndex == -1) {
			/* find the next spot for a new vertex */
			vertDataIndex = PicoGetSurfaceNumVertexes(workSurface);

			/* assign the data to it */
			PicoSetSurfaceXYZ(workSurface, vertDataIndex, *xyz[i]);
			PicoSetSurfaceNormal(workSurface, vertDataIndex, *normals[i]);

			/* make sure to copy over all available ST's and colors for the vertex */
			for (j = 0; j < numColors; j++) {
				PicoSetSurfaceColor(workSurface, j, vertDataIndex, colors[i][j]);
			}
			for (j = 0; j < numSTs; j++) {
				PicoSetSurfaceST(workSurface, j, vertDataIndex, st[i][j]);
			}

			PicoSetSurfaceSmoothingGroup(workSurface, vertDataIndex, smoothingGroup[i]);
		}

		/* add this vertex to the triangle */
		PicoSetSurfaceIndex(workSurface, newVertIndex, vertDataIndex);
	}
}