/* Entity and animation database functions */
#include "gameinc.h"

/* Strat include */
#include "strats.h"

/* Some global variables */
p_LinkListHead entity_editing_list;
p_LinkListHead entity_level_list;

/* Some static variables */
static br_fmt_results *entityresults = NULL;

static struct ani_frame entity_multiframes[MAXGROUPS][MAXFRAMES];
static struct ani_transform *entity_multitransforms=NULL;
static int entity_multitotal_frames[MAXGROUPS];

static int entity_loadedanimations=0;


/* Static functions */
// FIXME This structure for animations is a pile of poo, fix this so it is dynamic and tidy and not
// a hack.
static void entity_AttachVUE(char *file_name, br_actor * root)
{
	FILE           *file;
	int             f = -1, i, firstflag=0,bodgeoff=0;
	char            buff[1024];
	char            name[80];
	float           v[4][3];
	struct ani_transform *t;
	struct ani_frame *p_f = entity_multiframes[entity_loadedanimations];
	static int numtloaded=0;

	t= entity_multitransforms+numtloaded;	

	entity_multitotal_frames[entity_loadedanimations]=0;
	file = fopen(file_name, "r");

	if (file == NULL)
	{
		sprintf(buff,"Animation file '%s' not found!",file_name);
		fatal(buff);
	}

	while (!feof(file)) {
		fgets(buff, 1024, file);

		/* Is it a frame specification line? */

		if (sscanf(buff, "frame %d", &i) > 0) {
			if (firstflag==0)
			{
				firstflag=1;
				bodgeoff=i;
			}
			i=i-bodgeoff;
			if (f >= 0)
				p_f[f].ntransforms = t - p_f[f].transforms;
			f = i;
			p_f[f].transforms = t;
		}
		/* Or a transform specification? */

		if (sscanf(buff,
		 "transform \"%[^\"]\" %f %f %f %f %f %f %f %f %f %f %f %f",
				name,
				&v[0][0], &v[0][1], &v[0][2],
				&v[1][0], &v[1][1], &v[1][2],
				&v[2][0], &v[2][1], &v[2][2],
				&v[3][0], &v[3][1], &v[3][2]) > 0
			) {
			int             k, l;

			/* Found a transform so convert it to scalars */

			for (k = 0; k < 4; k++)
				for (l = 0; l < 3; l++)
					t->mat.m[k][l] = BrFloatToScalar(v[k][l]);

			t->actor = Editor_SearchTreeNew(root, name);

			if (t->actor != NULL)
				t++;

			numtloaded++;
			if (numtloaded>=MAXTRANSFORMS)
			{
				fatal("Maximum transforms reached!!");
				BR_ERROR0("Maximum transforms reached!!");
				fclose(file);
				PostQuitMessage(0);
				return;
			}
		}
	}

	fclose(file);

	if (f >= 0)
		p_f[f].ntransforms = t - p_f[f].transforms;

	entity_multitotal_frames[entity_loadedanimations] = f + 1;

	entity_loadedanimations++;
}



br_error CompileEntityFile(br_fmt_results *results,char *basepath,char *basename)
{
	int i;
	br_material **material;
	br_scalar value;
	br_pixelmap *pixtemp;
	char temp[256];
	char pixmappath[256];
	char pixmappath2[256];
	char pixmapname[256];
	void *fh;
	int allpix=0;
	br_pixelmap *allpixelmap[2048];

	if (results==NULL)
		return BRE_OK;

	Editor_OverlayDebug("    Compiling entity");
	if (results->nmaterials>0)
		BrFmtScriptMaterialSaveMany("d:\\cult\\data\\mat.scp",results->materials,(br_uint_16) results->nmaterials);
//XXX	AllLightsOffActor(results->actors[0]);
	BrActorSaveMany("d:\\cult\\data\\bits.act",results->actors,(br_uint_16) results->nactors);
	BrWriteModeSet(BR_FS_MODE_TEXT);
	BrActorSaveMany("d:\\cult\\data\\act.txt",results->actors,(br_uint_16) results->nactors);
	BrWriteModeSet(BR_FS_MODE_BINARY);
	BrModelRemoveMany(results->models,(br_uint_16) results->nmodels);
	BrModelSaveMany("d:\\cult\\data\\bits.dat",results->models,(br_uint_16) results->nmodels);
	if (results->nmaterials>0)
		BrMaterialRemoveMany(results->materials,(br_uint_16) results->nmaterials);
//	BrMapRemoveMany(results->pixelmaps,results->npixelmaps);

	sprintf(pixmappath,"%s\\%s.pix",basepath,basename);
	if (results->npixelmaps>0)
	{
	fh = BrFileOpenRead(pixmappath,0,NULL,NULL);
	if ( fh != NULL)
	{
		sprintf(temp,"      Loading all texturemaps in one block");
		Editor_OverlayDebug(temp);
		allpix=1;
		BrFileClose(fh);
		i=BrPixelmapLoadMany(pixmappath,allpixelmap,2048);
		BrMapAddMany(allpixelmap,i);
	}
	else
	{
	for (i=0;i<(int) results->npixelmaps;i++)
	{
		pixtemp=results->pixelmaps[i];
		if (pixtemp == NULL)
		{
			fatal("erkness happened!!!\n");
		}

		strcpy(pixmappath,basepath);
		strcat(pixmappath,"\\");
		strcat(pixmappath,pixtemp->identifier);
//		strcat(pixmappath,".gif");
		strcat(pixmappath,".tga");

		strcpy(pixmappath2,basepath);
		strcat(pixmappath2,"\\");
		strcat(pixmappath2,pixtemp->identifier);
		strcat(pixmappath2,".pix");

		strcpy(pixmapname,pixtemp->identifier);
		BrMapRemove(pixtemp);
		BrPixelmapFree(pixtemp);

		pixtemp=NULL;
		fh = BrFileOpenRead(pixmappath2,0,NULL,NULL);
		if (fh != NULL)
		{
//			sprintf(temp,"      Loading texturemap %d called '%s'",i+1,pixmappath);
//			Editor_OverlayDebug(temp);
 			BrFileClose(fh);
			pixtemp=BrPixelmapLoad(pixmappath2);
		}
		else
		{
			fh = BrFileOpenRead(pixmappath,0,NULL,NULL);
			if (fh != NULL)
			{
//				sprintf(temp,"      Loading texturemap %d called '%s'",i+1,pixmappath);
//				Editor_OverlayDebug(temp);
 				BrFileClose(fh);
//				pixtemp=BrFmtGIFLoad(pixmappath,0);
				pixtemp=BrFmtTGALoad(pixmappath,0);
			}
		}
		if (pixtemp==NULL)
		{
			sprintf(temp,"      *** Failed to find texturemap %d called '%s'",i+1,pixmappath);
			Editor_OverlayDebug(temp);
//			pixtemp=BrPixelmapAllocate(BR_PMT_INDEX_8,1,1,NULL,BR_PMAF_NORMAL);
//			pixtemp->map=BrPixelmapAllocate(BR_PMT_RGBX_888,1,256,NULL,BR_PMAF_NORMAL);
			pixtemp=BrPixelmapLoad("d:\\cult\\data\\maps\\blank.pix");
		}
		pixtemp->identifier=BrMemStrDup(pixmapname);
		results->pixelmaps[i]=pixtemp;
	}
	BrMapAddMany(results->pixelmaps,results->npixelmaps);
	}
	}

	if (results->nmaterials>0)
	{
	BrFmtScriptMaterialLoadMany("d:\\cult\\data\\mat.scp",results->materials,(br_uint_16) results->nmaterials);

	material=results->materials;
	for (i=0;i<(int) results->nmaterials;i++)
	{
		if (material[i]->ka==0)
		{
			value=BR_SCALAR(0.098039);
			material[i]->ka=BrScalarToUFraction(value);
		}
		if (material[i]->kd==0)
		{
			value=BR_SCALAR(0.698039);
			material[i]->kd=BrScalarToUFraction(value);
		}

		if (material[i]->colour==0)
		{
			material[i]->colour=BR_COLOUR_RGB(178,178,178);
		}		

	}

	BrMaterialAddMany(results->materials,results->nmaterials);
	}

	results->nmodels=BrModelLoadMany("d:\\cult\\data\\bits.dat",results->models,(br_uint_16) results->nmodels);
	for (i=0;i<(int)results->nmodels;i++)
	{
		results->models[i]->flags =BR_MODF_KEEP_ORIGINAL;
	}

	BrModelAddMany(results->models,(br_uint_16) results->nmodels);

	BrActorLoadMany("d:\\cult\\data\\bits.act",results->actors,(br_uint_16) results->nactors);

/*XXX
	switch (editor_editmode)
	{
		case EDITMODE_GAME:
		case EDITMODE_GENERIC:
		case EDITMODE_LIGHTS:
			BrActorAdd(sceneactor,results->actors[0]);
			break;
		case EDITMODE_ANIMATION:
			BrActorAdd(anim_world,results->actors[0]);
			break;
	}
*/

//	UpdateWLightList(results->actors[0]);
//XXX	UpdateWLightList(results);

	if (results->nmaterials>0)
		BrFmtScriptMaterialSaveMany("d:\\cult\\data\\matafter.scp",results->materials,(br_uint_16) results->nmaterials);
	if (results->npixelmaps>0)
	{
		BrPixelmapSaveMany("d:\\cult\\data\\pix.pix",results->pixelmaps,(br_uint_16) results->npixelmaps);
	}

}


static BR_CALLBACK sendthetext(char *string)
{
	Editor_OverlayDebug(string);

	return 0;
}


static void entity_loadupresources( p_E_Entity this, char *file )
{
	char *bit;
	br_fmt_options fmt_options;
	br_3ds_options options;
	char buff[256],buff2[256];

	/* Copy name extracting the base path and the entity file name*/
	strcpy(buff2,file);
	bit=strrchr(buff2,'.');
	if (bit!=NULL)
		bit[0]=0;	

	bit=strrchr(buff2,'\\');
	if (bit!=NULL)
		bit[0]=0;	


	sprintf(buff,"Loading entity file '%s'",bit+1);
	Editor_OverlayDebug(buff);
	fmt_options.convert_flags=BR_FMT_CONVERT_ALL;

	if ( this->transform_type == ENTITY_TRANSFORM_FLAT )
	{
		/* This option works with Owens stuff */
		options.flags=BR_3DS_FLAT_HIERARCHY |
						BR_3DS_SET_PERSPECTIVE |
//						BR_3DS_CORRECT_AXES |
						BR_3DS_APPLY_MESH_MATRIX |
//						BR_3DS_APPLY_PIVOT |
						0;
	}

	if ( this->transform_type == ENTITY_TRANSFORM_HIERARCHY )
	{
		options.flags=//BR_3DS_FLAT_HIERARCHY |
						BR_3DS_SET_PERSPECTIVE |
//						BR_3DS_CORRECT_AXES |
						BR_3DS_APPLY_MESH_MATRIX |
						BR_3DS_APPLY_PIVOT |
						0;
	}

	options.report = sendthetext;
					
	entityresults=MBrFmt3DSLoad(file,&fmt_options,&options);

	strcpy(buff2,file);
	bit=strrchr(buff2,'.');
	if (bit!=NULL)
		bit[0]=0;	

	bit=strrchr(buff2,'\\');
	if (bit!=NULL)
		bit[0]=0;	

	CompileEntityFile(entityresults,buff2,bit+1);

}


/***********************************************************************************/
/***********************************************************************************/
/***********************************************************************************/
/* Entity functions */
/***********************************************************************************/
/***********************************************************************************/
/***********************************************************************************/

void Entity_Init(void)
{
	int mytemp;

	entity_editing_list=LinkList_Create();
	entity_level_list=LinkList_Create();

   if (entity_multitransforms==NULL)
   {
      mytemp=sizeof(struct ani_transform)*MAXTRANSFORMS;
      entity_multitransforms=BrMemAllocate(mytemp,BR_MEMORY_APPLICATION);
   }
}

void Entity_InitForEditor(void)
{

	Editor_OverlayDebug("Init entities for editor");

}


void dumpmatrixtodebug(br_matrix34 *m)
{
	int k, l;
	float v[12];
	char buff[1024];

 	/* Dump a matrix */
	for (k = 0; k < 4; k++)
		for (l = 0; l < 3; l++)
			v[k*3+l] = BrScalarToFloat(m->m[k][l]);
	sprintf(buff,
		"transform %f %f %f %f %f %f %f %f %f %f %f %f",v[0], v[1], v[2],v[3], v[4], v[5],
			v[6], v[7], v[8],v[9], v[10], v[11]);
	Editor_OverlayDebug(buff);
	/* End of hack */
}


static void spawnspider(void)
{
	p_E_Entity this;

	/* Try making a spider work */
	this = Entity_Create();
	this->identifier = 2;
	this->anim_first_identifier = entity_loadedanimations;
	this->transform_type = ENTITY_TRANSFORM_FLAT;
	entity_loadupresources(this,"p:\\cult\\veryt\\spider.3ds");
	entityresults->actors[0]->t.type=BR_TRANSFORM_MATRIX34;
	BrMatrix34PreRotateX(&entityresults->actors[0]->t.t.mat, BR_ANGLE_DEG(-90.0));
   this->rootactor = BrActorAllocate(BR_ACTOR_NONE, NULL);
	this->rootactor->t.type=BR_TRANSFORM_MATRIX34;
	BrActorAdd(this->rootactor,entityresults->actors[0]);
	
	entity_AttachVUE("p:\\cult\\veryt\\spider.vue",this->rootactor);
	this->anim_identifier = 0;

	BrMatrix34Translate(&this->worldpos, BR_SCALAR(150.0 + (rand()%200) ), BR_SCALAR(0.0), BR_SCALAR(-150.0 + (rand()%200)));
	BrMatrix34PreRotateY(&this->worldpos, BR_ANGLE_DEG(rand()%360));
	BrActorAdd(game_worldactor,this->rootactor);
	BrMatrix34Copy(&this->rootactor->t.t.mat,&this->worldpos);
//	dumpmatrixtodebug(&this->rootactor->t.t.mat);
	this->anim_last_identifier = entity_loadedanimations;
	this->anim_total_identifiers = this->anim_last_identifier - this->anim_first_identifier;
	this->anim_callback = STRAT_CycleEntityMove;
	Entity_SendMessageToOne(ENTITY_MESSAGE_SYSTEM_STARTUP,this);
	Entity_SendMessageToOne(ENTITY_MESSAGE_INSTANCE_STARTUP,this);
	this->linklist = LinkList_Add(entity_level_list,this);
}


void Entity_InitForGame(void)
{
	p_E_Entity this;

	Editor_OverlayDebug("Init entities for game");


#if 1
	this = Entity_Create();
	this->identifier = 2;
	this->anim_first_identifier = entity_loadedanimations;
	this->transform_type = ENTITY_TRANSFORM_FLAT;
	entity_loadupresources(this,"p:\\cult\\martinp\\finalnat\\nat.3ds");
	entityresults->actors[0]->t.type=BR_TRANSFORM_MATRIX34;
	BrMatrix34PreRotateX(&entityresults->actors[0]->t.t.mat, BR_ANGLE_DEG(-90.0));
   this->rootactor = BrActorAllocate(BR_ACTOR_NONE, NULL);
	this->rootactor->t.type=BR_TRANSFORM_MATRIX34;
	BrActorAdd(this->rootactor,entityresults->actors[0]);
	
	BrMatrix34Translate(&this->worldpos, BR_SCALAR(0.0), BR_SCALAR(0.0), BR_SCALAR(0.0));
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\stand.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\walk.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\run-side.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\stndlp.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\stndlp2.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\stndlp.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\idle2.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\gunfire.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\handfire.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\climbt.vue",this->rootactor);
// 10
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\sidestep.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\walkgun3.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\run+fire.vue",this->rootactor);
	entity_AttachVUE("p:\\cult\\martinp\\finalnat\\levitate2.vue",this->rootactor);
	this->anim_identifier = 0;
	this->anim_frame = 0;

	BrActorAdd(game_worldactor,this->rootactor);
	BrMatrix34Copy(&this->rootactor->t.t.mat,&this->worldpos);
	this->anim_last_identifier = entity_loadedanimations;
	this->anim_total_identifiers = this->anim_last_identifier - this->anim_first_identifier;
	this->anim_callback = Resource_Find(RESOURCE_TYPE_HANDLER,"PLAYER_NATHAN");
	Entity_SendMessageToOne(ENTITY_MESSAGE_SYSTEM_STARTUP,this);
	Entity_SendMessageToOne(ENTITY_MESSAGE_INSTANCE_STARTUP,this);
	this->linklist = LinkList_Add(entity_level_list,this);
#endif

#if 0
	this = Entity_Create();
	this->identifier = 2;
	this->anim_first_identifier = entity_loadedanimations;
	this->transform_type = ENTITY_TRANSFORM_FLAT;
	entity_loadupresources(this,"p:\\cult\\level1\\vancdonly.3ds");
	entityresults->actors[0]->t.type=BR_TRANSFORM_MATRIX34;
	BrMatrix34PreRotateX(&entityresults->actors[0]->t.t.mat, BR_ANGLE_DEG(-90.0));
   this->rootactor = BrActorAllocate(BR_ACTOR_NONE, NULL);
	this->rootactor->t.type=BR_TRANSFORM_MATRIX34;
	BrActorAdd(this->rootactor,entityresults->actors[0]);
	
	BrMatrix34Translate(&this->worldpos, BR_SCALAR(0.0), BR_SCALAR(0.0), BR_SCALAR(0.0));
	entity_AttachVUE("p:\\cult\\level1\\vancell.vue",this->rootactor);
	this->anim_identifier = 0;
	this->anim_frame = 0;

	BrActorAdd(game_worldactor,this->rootactor);
	BrMatrix34Copy(&this->rootactor->t.t.mat,&this->worldpos);
	this->anim_last_identifier = entity_loadedanimations;
	this->anim_total_identifiers = this->anim_last_identifier - this->anim_first_identifier;
	this->anim_callback = STRAT_CycleEntity;
	Entity_SendMessageToOne(ENTITY_MESSAGE_SYSTEM_STARTUP,this);
	Entity_SendMessageToOne(ENTITY_MESSAGE_INSTANCE_STARTUP,this);
	this->linklist = LinkList_Add(entity_level_list,this);

#endif

}


p_E_Entity Entity_Create(void)
{
	p_E_Entity this;

	this = calloc(1,sizeof(struct s_E_Entity));

	BrMatrix34Identity(&this->editpos);
	BrMatrix34Identity(&this->worldpos);

	this->anim_first_identifier = -1;
	this->anim_last_identifier = -1;

	this->tweentime = 0.1F;

	return this;
}


/* "Morph" one matrix to another for the purposes of tweening animation
 */
static void E_ZoomToMatrix34(br_matrix34 *a, br_matrix34 *b, float speed)
{
    int i, j;

    for(i = 0; i < 4; i++)
        for(j = 0; j < 3; j++)
            a->m[i][j] = BR_ADD(BR_MUL(a->m[i][j], BR_SCALAR(1-speed)),
                                BR_MUL(b->m[i][j], BR_SCALAR(speed)));
}


void Entity_SetAnimFrame(p_E_Entity this,int currentgroup,int current_frame)
{
	int i;

	currentgroup +=this->anim_first_identifier;
	if (entity_multitotal_frames[currentgroup] != 0)
	{
		// Clamp frame number to valid range.

		if (current_frame < 0)
			current_frame = entity_multitotal_frames[currentgroup]-1;
	  
		if (current_frame >= entity_multitotal_frames[currentgroup])
			current_frame = 0;


		// Apply animation to entity.
		for (i = 0; i < entity_multiframes[currentgroup][current_frame].ntransforms; i++)
		{
			if (this->morphtime > 0.0F)
			{
				E_ZoomToMatrix34(&entity_multiframes[currentgroup][current_frame].transforms[i].actor->t.t.mat,
										&entity_multiframes[currentgroup][current_frame].transforms[i].mat,1.0F - this->morphtime);
			}
			else
			{
				entity_multiframes[currentgroup][current_frame].transforms[i].actor->t.t.mat =
					entity_multiframes[currentgroup][current_frame].transforms[i].mat;
			}
		}
		if (this->morphtime > 0.0F)
		{
			this->morphtime -= this->tweentime;
		}

	}

	this->anim_identifier = currentgroup - this->anim_first_identifier;
	this->anim_frame = current_frame;
}


void Entity_SendMessageToAll(int message)
{
	p_E_Entity this;
	p_LinkList entity, entitynext;

	entity=entity_level_list->start;
	while (entity)
	{
		this = (p_E_Entity) entity->data;

		entitynext=entity->next;
		if ( this->anim_callback != NULL)
		{
			(*this->anim_callback)(message,this);
		}


		entity=entitynext;
	}
}


void Entity_SendMessageToOne(int message,	p_E_Entity this)
{

	if ( this->anim_callback != NULL)
	{
		(*this->anim_callback)(message,this);
	}
}


br_fmt_results *Entity_LoadAModelCollection(p_E_Entity this,char *filename)
{

	Editor_OverlayDebug("    *** Spawning sub-entity model collection");

	entity_loadupresources(this,filename);

	return entityresults;
}


void bunchofspiders(void)
{
	p_E_Entity this;
	br_actor *tempact;

	e_console_flags=2;

	/* Try making a spider work */
	spawnspider();
	spawnspider();
	spawnspider();
	spawnspider();
	spawnspider();
	spawnspider();

#if 1
	/* This is a Wraith */
	this = Entity_Create();
	this->identifier = 2;
	this->anim_first_identifier = entity_loadedanimations;
	this->transform_type = ENTITY_TRANSFORM_FLAT;
	entityresults->actors[0]->t.type=BR_TRANSFORM_MATRIX34;
   this->rootactor = BrActorAllocate(BR_ACTOR_NONE, NULL);
	this->rootactor->t.type=BR_TRANSFORM_MATRIX34;

	tempact = BrActorAllocate(BR_ACTOR_MODEL, NULL);
	BrMatrix34PreRotateX(&tempact->t.t.mat, BR_ANGLE_DEG(-90.0));
	BrActorAdd(this->rootactor,tempact);
	
	BrMatrix34Translate(&this->worldpos, BR_SCALAR(0.0), BR_SCALAR(0.0), BR_SCALAR(0.0));

	BrActorAdd(game_worldactor,this->rootactor);
	BrMatrix34Copy(&this->rootactor->t.t.mat,&this->worldpos);
	this->anim_callback = STRAT_WraithEntity;
	Entity_SendMessageToOne(ENTITY_MESSAGE_SYSTEM_STARTUP,this);
	Entity_SendMessageToOne(ENTITY_MESSAGE_INSTANCE_STARTUP,this);
	this->linklist = LinkList_Add(entity_level_list,this);
#endif

	e_console_flags=0;
}



// FIXME Add in some compression to these functions. ie. Use shorts and don't store unchanged verts
// like the MIME format used for Playstation.
void *Anim_FiniteDifferenceCalculate(br_model *source,br_model *out)
{
	int i,numverts;
	float *differences;
	float x1,y1,z1,x2,y2,z2;

	if (source->nvertices != out->nvertices)
	{
		fatal("Source and destination do not have the same number of vertices");
	}

	if (source->nfaces != out->nfaces)
	{
		fatal("Source and destination do not have the same number of vertices");
	}

	numverts = source->nvertices;
	differences = calloc(1,sizeof(float)*3*numverts);
	if (differences == NULL)
	{
		fatal("Failed to allocate memory for morph space");
	}

	for (i=0;i<numverts;i++)
	{
		x1 = BrScalarToFloat(source->vertices[i].p.v[0]);
		y1 = BrScalarToFloat(source->vertices[i].p.v[1]);
		z1 = BrScalarToFloat(source->vertices[i].p.v[2]);

		x2 = BrScalarToFloat(out->vertices[i].p.v[0]);
		y2 = BrScalarToFloat(out->vertices[i].p.v[1]);
		z2 = BrScalarToFloat(out->vertices[i].p.v[2]);

		differences[i*3+0] = x2-x1;
		differences[i*3+1] = y2-y1;
		differences[i*3+2] = z2-z1;
	}

	return (void *) differences;
}


void *Anim_FiniteDifferenceCalculateStart(br_model *source)
{
	int i,numverts;
	float *allocated;

	numverts = source->nvertices;
	allocated = calloc(1,sizeof(float)*3*numverts);
	if (allocated == NULL)
	{
		fatal("Failed to allocate memory for morph space Start");
	}

	for (i=0;i<numverts;i++)
	{
		allocated[i*3+0] = BrScalarToFloat(source->vertices[i].p.v[0]);
		allocated[i*3+1] = BrScalarToFloat(source->vertices[i].p.v[1]);
		allocated[i*3+2] = BrScalarToFloat(source->vertices[i].p.v[2]);
	}

	return (void *) allocated;
}


void Anim_FiniteDifferenceStart(br_model *source,void *pstart)
{
	int i,numverts;
	float *start = (float *) pstart;

	numverts = source->nvertices;

	for (i=0;i<numverts;i++)
	{
		source->vertices[i].p.v[0] = BR_SCALAR(start[i*3+0]);
		source->vertices[i].p.v[1] = BR_SCALAR(start[i*3+1]);
		source->vertices[i].p.v[2] = BR_SCALAR(start[i*3+2]);
	}

}


void Anim_FiniteDifferenceMorphTo(br_model *source,void *pstart,float fraction)
{
	int i,numverts;
	float *start = (float *) pstart;

	numverts = source->nvertices;

	for (i=0;i<numverts;i++)
	{
		source->vertices[i].p.v[0] = BR_SCALAR(BrScalarToFloat(source->vertices[i].p.v[0])+(start[i*3+0]*fraction));
		source->vertices[i].p.v[1] = BR_SCALAR(BrScalarToFloat(source->vertices[i].p.v[1])+(start[i*3+1]*fraction));
		source->vertices[i].p.v[2] = BR_SCALAR(BrScalarToFloat(source->vertices[i].p.v[2])+(start[i*3+2]*fraction));
	}

}

