/*--------------------------------------------------------------------------
 * File: v3o.c
 * Written by: Alexander Boczar, 1997-04-16
 * Description: Saga 3d Object (v3o) (loader) saver.
 *
 * Updates:
 * -- Date -- | ----- Name ----- |-- Did what....
 * 1997-xx-xx | Alexander Boczar |
 * 1997-05-09 | Fredrik Kling 	 | loader + uppdaterade saver och r„ttade buggar
 * 1997-05-12 | Fredrik Kling 	 | bugg fix i loadern....
 *
 * Todo:
 *
 *
 -------------------------------------------------------------------------------*/

#include "system/xstring.h"
#include "system/xstdio.h"
#include "system/xstdlib.h"
#include "system/xstddef.h"
#include "system/xmath.h"
#include "formats/v3o.h"
#include "formats/vio.h"
#include "formats/tga.h"
#include "formats/gif.h"
#include "vmath/vector.h"
#include "objects/texture.h"


#define VERSION 0x0125

typedef enum
{
	ERR_NOERR,
	ERR_NOFILE,
	ERR_NOMEM,
  ERR_NOTV3O,
  ERR_WRONGVER,
  ERR_CUSTOM,
} ERROR;

static ERROR error = ERR_NOERR;
static char errstr[256];

void v3o_dump (V3O *obj,int dc,int ds)
{
	int i;
  printf ("-þ- Dumping V3O, version %x -þ-\n",VERSION);
	printf ("  Name....:%s\n",obj->name);
	printf ("  Vertexes:%i\n",obj->numvertex);
	printf ("  Surfaces:%i\n",obj->numsurface);
	printf ("  Material:%i\n",obj->nummaterial);
	printf ("  Textures:%i\n",obj->numtexture);
	if ((obj->nummaterial != 0))
	{
		printf ("  Materiallist:\n");
		for (i=0;i<obj->nummaterial;i++)
		{
			printf ("    m%3d: '%s' (%d,%d,%d) ", i, obj->material[i].name, obj->material[i].color.r, obj->material[i].color.g, obj->material[i].color.b);
			if( obj->material[i].flags & V3OMATERIALFLAG_FLAT)
				printf("Flat,");
			if( obj->material[i].flags & V3OMATERIALFLAG_GOURADE)
				printf("Gourade,");
			if( obj->material[i].flags & V3OMATERIALFLAG_TEXTURE)
				printf("Texture[%d],", obj->material[i].texture);
			if( obj->material[i].flags & V3OMATERIALFLAG_ENVMAP)
				printf("Envmap[%d],", obj->material[i].texture);
			printf("\x08 \x08\n");
		}
	}
	if ((obj->numtexture != 0))
	{
		printf ("  Texturelist:\n");
		for (i=0;i<obj->numtexture;i++)
		{
			printf ("    t%3d: '%s'\n", i, obj->texture[i].filename);
		}
	}
	if ((obj->numvertex!=0) && (dc))
	{
		printf ("  Vertexlist:\n");
		for (i=0;i<obj->numvertex;i++)
			printf ("    p%3i: %6.3f,%6.3f,%6.3f\n",i,obj->orgvertex[i].x,obj->orgvertex[i].y,obj->orgvertex[i].z);
	}
	if ((obj->numsurface!=0) && (ds))
	{
		printf ("  Surfacelist:\n");
		for (i=0;i<obj->numsurface;i++)
		{

			if (obj->surface[i].flags & V3OSURFACEFLAG_POINT)
			{
				printf ("    s%3i:  f: %i - (%i)\n",i,obj->surface[i].flags,obj->surface[i].v1);
			}
			else if ( obj->surface[i].flags & V3OSURFACEFLAG_LINE)
			{
				printf ("    s%3i:  f: %i - (%i,%i)\n",i,obj->surface[i].flags,obj->surface[i].v1,obj->surface[i].v2);
			}
			else
			{
				printf ("    s%3i: m:%i, f:%i - (%i,%i,%i) tex: (%f,%f),(%f,%f),(%f,%f)\n",i,obj->surface[i].material,obj->surface[i].flags,obj->surface[i].v1,obj->surface[i].v2,obj->surface[i].v3,
																																									obj->surface[i].tx1,obj->surface[i].ty1,obj->surface[i].tx2,obj->surface[i].ty2,obj->surface[i].tx3,obj->surface[i].ty3);
			}
		}
	}

}
V3O *v3o_create (void)
{
	V3O *v3o;

	if ((v3o=xmalloc (sizeof (V3O)))==NULL)
	{
		error = ERR_NOMEM;
		return NULL;
	}

	strcpy (v3o->name," ");
	v3o->flags=0;
	v3o->nummaterial=0;
	v3o->numtexture=0;
	v3o->numsurface=0;
	v3o->numvertex=0;

	v3o->material=NULL;
	v3o->texture=NULL;
	v3o->surface=NULL;

	v3o->orgvertex=NULL;
	v3o->orgnormal=NULL;
	v3o->rotvertex=NULL;
	v3o->rotnormal=NULL;
	v3o->projvertex=NULL;

	return v3o;
}
/*
int v3o_addmtrl (V3O *v3o,V3OMATERIAL *mtrl)
{
	V3OMATERIAL *newmtrl;
	if (v3o->nummaterial==0)
	{
		v3o->nummaterial=1;
		v3o->material=mtrl;
	} else {
					 v3o->nummaterial++;
					 newmtrl=(V3OMATERIAL *)realloc (v3o->material,sizeof (V3OMATERIAL) * v3o->nummaterial);
					 if (newmtrl==NULL)
					 {
							error = ERR_NOMEM;
							return -1;
					 }
					 v3o->material=newmtrl;
					 v3o->material[v3o->nummaterial-1]=*mtrl;
				 }
	return (v3o->nummaterial);
}
V3OMATERIAL *v3o_createstdmtrl (void)
{
	V3OMATERIAL *mtrl;
	if ((mtrl = (V3OMATERIAL *) xmalloc (sizeof (V3OMATERIAL)))==NULL)
	{
		error = ERR_NOMEM;
		return NULL;
	}


	sprintf (mtrl->name,"STD MAT V1.0");
	mtrl -> texture = 0;
	mtrl -> phongmap = 0;
	mtrl -> flags = V3OMATERIALFLAG_GOURADE;
	mtrl -> color.r=48;
	mtrl -> color.g=48;
	mtrl -> color.b=48;

	return (mtrl);
}
void v3o_setmtrl (V3O *v3o, int mtrl)
{
	int i;
	for (i=0;i<v3o->numsurface;i++)
		v3o->surface[i].material=mtrl;
}
*/
int v3o_alloc (V3O *obj)
{
	if (obj->nummaterial>0)
		if ((obj->material=(V3OMATERIAL *)xmalloc (sizeof(V3OMATERIAL) * obj->nummaterial))==NULL)
		{
			error = ERR_NOMEM;
			return 0;
		}
	if (obj->numtexture>0)
		if ((obj->texture=(V3OTEXTURE *)xmalloc (sizeof(V3OTEXTURE) * obj->numtexture))==NULL)
		{
			error = ERR_NOMEM;
			return 0;
		}
	if (obj->numvertex>0)
	{
		if ((obj->orgvertex=(VECTOR *)xmalloc (sizeof(VECTOR) * obj->numvertex))==NULL) { error = ERR_NOMEM; return 0; }
		if ((obj->rotvertex=(VECTOR *)xmalloc (sizeof(VECTOR) * obj->numvertex))==NULL) { error = ERR_NOMEM; return 0; }
		if ((obj->projvertex=(VECTOR *)xmalloc (sizeof(VECTOR) * obj->numvertex))==NULL) { error = ERR_NOMEM; return 0; }
		if ((obj->orgnormal=(VECTOR *)xmalloc (sizeof(VECTOR) * obj->numvertex))==NULL) { error = ERR_NOMEM; return 0; }
		if ((obj->rotnormal=(VECTOR *)xmalloc (sizeof(VECTOR) * obj->numvertex))==NULL) { error = ERR_NOMEM; return 0; }
	}
	if (obj->numsurface>0)
		if ((obj->surface=(V3OSURFACE *)xmalloc (sizeof(V3OSURFACE) * obj->numsurface))==NULL)
		{
			error = ERR_NOMEM;
			return 0;
		}
	return 1;
}

/*############################################################################
#
# V3O Loader
#
############################################################################*/

V3O *v3o_load( char *filename, char *imagepath)
{
	V3O *obj = NULL;
	XFILE *f;
	int i;
	DWORD v;

	if ((f = xfopen(filename, "rb")) == NULL)
	{
		error = ERR_NOFILE;
		return (NULL);
	}


  //printf("Reading header\n");

  if (xfrle_dword (f) != 'V3O\0')
  {
    error = ERR_NOTV3O;
    return (NULL);
  }
  if ((v=xfrle_word (f)) != VERSION)
  {
    error = ERR_WRONGVER;
    return (NULL);
  }
//	printf ("þ V3O file identified, version: %x\n",v);



	if ((obj = v3o_create ())==NULL) return NULL;

	xfread (obj->name, sizeof (char),32,f);
	obj->flags = xfrbe_dword (f);


	// L„s in antal av det mesta...

	obj->nummaterial = xfrbe_dword (f); 	// Material
	obj->numtexture = xfrbe_dword (f);		// Texturer
	obj->numsurface = xfrbe_dword (f);		// Ytor
	obj->numvertex = xfrbe_dword (f); 		// Punkter


	// Allokera upp minne!!
	if (!v3o_alloc (obj)) return NULL;

	// L„s in texturerna...

  //printf("Reading textures: %d\n", obj->numtexture);
	for( i=0; i<obj->numtexture; i++)
	{
		char imagename[256];

		xfread( obj->texture[i].filename, sizeof( char), 64, f);
		obj->texture[i].flags = xfrbe_dword(f);

    if( (imagepath != NULL) && (strlen( imagepath) > 0))
			sprintf( imagename, "%s/%s", imagepath, obj->texture[i].filename);
		else
			strcpy( imagename, obj->texture[i].filename);
		obj->texture[i].image=texture_fetch( imagename);
	}

	// L„s in material

  //printf("Reading materials: %d\n", obj->nummaterial);
	for (i=0;i<obj->nummaterial;i++)
	{
		xfread (obj->material[i].name, sizeof( char), 64, f);
    obj->material[i].flags = xfrbe_dword (f);

		xfread (&obj->material[i].color, sizeof( RGB), 1, f);
		obj->material[i].texture = xfrbe_dword (f);

		//
		// Preset pointers...
		// M†ste fixa pekarna till att peka p† inl„sta texturer...
		//
		obj->material[i].phongmap = NULL;
	}

	// L„s in punkter...

  //printf("Reading vertexes: %d\n", obj->numvertex);
	for( i=0; i<obj->numvertex; i++)
	{
		obj->orgvertex[i].x = xfrbe_float(f);
		obj->orgvertex[i].y = xfrbe_float(f);
		obj->orgvertex[i].z = xfrbe_float(f);
	}

	// L„s in ytor...

  //printf("Reading surfaces: %d\n", obj->numsurface);
	for( i=0; i<obj->numsurface; i++)
	{
		obj->surface[i].flags = xfrbe_dword(f);
		obj->surface[i].material = xfrbe_dword(f);

		if ( obj->surface[i].flags & V3OSURFACEFLAG_POINT)
		{
			obj->surface[i].v1 = xfrbe_dword(f);
		}
		else if ( obj->surface[i].flags & V3OSURFACEFLAG_LINE)
		{
			obj->surface[i].v1 = xfrbe_dword(f);
			obj->surface[i].v2 = xfrbe_dword(f);
		}
		else if ( obj->surface[i].flags & V3OSURFACEFLAG_POLY)
		{
			if (obj->material[obj->surface[i].material].flags & V3OMATERIALFLAG_TEXTURE)
			{
				obj->surface[i].v1 = xfrbe_dword(f);
				obj->surface[i].v2 = xfrbe_dword(f);
				obj->surface[i].v3 = xfrbe_dword(f);

				obj->surface[i].tx1 = xfrbe_float(f);
				obj->surface[i].tx2 = xfrbe_float(f);
				obj->surface[i].tx3 = xfrbe_float(f);

				obj->surface[i].ty1 = xfrbe_float(f);
				obj->surface[i].ty2 = xfrbe_float(f);
				obj->surface[i].ty3 = xfrbe_float(f);
			}
			else
			{
				obj->surface[i].v1 = xfrbe_dword(f);
				obj->surface[i].v2 = xfrbe_dword(f);
				obj->surface[i].v3 = xfrbe_dword(f);
			}
		}
	}
/*
  //printf("Reading texture images: ?\n");
	for( i=0; i<obj->numtexture; i++)
	{
		if( obj->texture[i].flags & V3OTEXTUREFLAG_INCLUDED)
		{
			VIO *image;
      //printf("Reading included image\n");

			image = vio_read( f);
			if( image == NULL)
			{
				v3o_free( obj);
				return( NULL);
			}
			obj->texture[i].image = image;
			obj->texture[i].flags &= !V3OTEXTUREFLAG_INCLUDED;
		}
		else
		{
//			VIO *image;
//      //printf("Reading external image\n");
//			image = vio_load( obj->texture[i].filename);
//			if( image == NULL) image = tga_load( obj->texture[i].filename);
//			if( image == NULL) image = gif_load( obj->texture[i].filename);
//			if( image == NULL)
//			{
//				v3o_free( obj);
//				return( NULL);
//			}

//			vio_create8bit( image);
//			obj->texture[i].image = image;
		}
	}
*/
  //printf("Done!\n");
	// Klart!!

	xfclose( f);


	v3o_calcnormals (obj);
	return( obj);
}

/*############################################################################
#
# V3O Saver
#
############################################################################*/


int v3o_save_normal (char *filename, V3O *obj)
{
	FILE *f;
	int i;

	if ( (f = fopen( filename, "wb")) == NULL)
	{
		error = ERR_CUSTOM;
		sprintf (errstr,"[SAVE] Unable to open file: %s.",filename);
		return( FALSE);
	}

	fwle_dword( f, 'V3O\0');
	fwle_word( f, VERSION);

	/* Write Header */
	printf("Writing Header\n");

	fwrite (obj->name, sizeof( char), 32, f);
	fwbe_dword (f, obj->flags);

	fwbe_dword (f, obj->nummaterial);
	fwbe_dword (f, obj->numtexture);
	fwbe_dword (f, obj->numsurface);
	fwbe_dword (f, obj->numvertex);


	/* Write Textures */
	printf("Writing textures: %d\n",obj->numtexture);

	for( i=0; i<obj->numtexture; i++)
	{
		fwrite( obj->texture[i].filename, sizeof( char), 64, f);
		fwbe_dword( f, obj->texture[i].flags);
		if( obj->texture[i].flags & V3OTEXTUREFLAG_LOADED)
			obj->texture[i].flags |= V3OTEXTUREFLAG_INCLUDED;
	}

	/* Write Materials */
	printf("Writing materials: %d\n", obj->nummaterial);

	for(i=0; i<obj->nummaterial; i++)
	{
		fwrite (obj->material[i].name, sizeof( char), 64, f);
    fwbe_dword (f, obj->material[i].flags);

		fwrite( &obj->material[i].color, sizeof( RGB), 1, f);
	  fwbe_dword(f, obj->material[i].texture);
//		xbewrite_dword(f, obj->material[i].phongmap);
	}


	/* Write Vertexes */
	printf("Writing vertexes: %d\n", obj->numvertex);

	for( i=0; i<obj->numvertex; i++)
	{
		fwbe_float(f, obj->orgvertex[i].x);
		fwbe_float(f, obj->orgvertex[i].y);
		fwbe_float(f, obj->orgvertex[i].z);

	}


	/* Write Surfaces */
	printf("Writing surfaces: %d\n", obj->numsurface);

	for( i=0; i<obj->numsurface; i++)
	{
		fwbe_dword( f, obj->surface[i].flags);
		fwbe_dword( f, obj->surface[i].material);

		if ( obj->surface[i].flags & V3OSURFACEFLAG_POINT)
		{
			fwbe_dword( f, obj->surface[i].v1);
		}
		else if ( obj->surface[i].flags & V3OSURFACEFLAG_LINE)
		{
			fwbe_dword( f, obj->surface[i].v1);
			fwbe_dword( f, obj->surface[i].v2);
		}
		else if ( obj->surface[i].flags & V3OSURFACEFLAG_POLY)
		{
			if (obj->material[obj->surface[i].material].flags & V3OMATERIALFLAG_TEXTURE)
			{
				fwbe_dword( f, obj->surface[i].v1);
				fwbe_dword( f, obj->surface[i].v2);
				fwbe_dword( f, obj->surface[i].v3);

				fwbe_float( f, obj->surface[i].tx1);
				fwbe_float( f, obj->surface[i].tx2);
				fwbe_float( f, obj->surface[i].tx3);

				fwbe_float( f, obj->surface[i].ty1);
				fwbe_float( f, obj->surface[i].ty2);
				fwbe_float( f, obj->surface[i].ty3);
			}
			else
			{
				fwbe_dword( f, obj->surface[i].v1);
				fwbe_dword( f, obj->surface[i].v2);
				fwbe_dword( f, obj->surface[i].v3);
			}
		}
	}
/*
	printf("Writing texture images: ?\n");
	for( i=0; i<obj->numtexture; i++)
	{
		if( obj->texture[i].flags & V3OTEXTUREFLAG_INCLUDED)
			vio_write( f, obj->texture[i].image);
		obj->texture[i].flags &= !V3OTEXTUREFLAG_INCLUDED;
	}
*/
	fclose( f);

	return( TRUE);

}
int v3o_save_asm (char *filename, V3O *obj)
{
	int i;
	char matname[128];
	FILE *f;

	if ((f = fopen (filename,"wt"))==NULL)
	{
		error = ERR_CUSTOM;
		sprintf (errstr,"[SAVE] Unable to open file: %s.",filename);
		return( FALSE);
	}
	fprintf (f,";-------++-- Generated file --++------------\n");
	fprintf (f,"%s");
	fprintf (f,"        dd        %i         ; nummaterial\n",obj->nummaterial);
	fprintf (f,"          dd        %i          ; numvertex\n",obj->numvertex);
	fprintf (f,"          dd        %i          ; numsurface\n",obj->numsurface);
	fprintf (f,"          dd        %i          ; numtexture\n",obj->numtexture);
	fprintf (f,"          dd        ofs %s_sp    ; Surface pointer\n",filename);
	fprintf (f,"          dd        ofs %s_ov    ; Orgvertex\n",filename);
	fprintf (f,"          dd        ofs %s_on    ; Orgnormal\n",filename);
	fprintf (f,"          dd        ofs %s_rv    ; Rotvertex\n",filename);
	fprintf (f,"          dd        ofs %s_rn    ; Rotnormal\n",filename);
	fprintf (f,"          dd        ofs %s_pv    ; Projected vertex\n",filename);

	fprintf (f,"          dd        ");
	for (i=0;i<obj->nummaterial;i++)
	{
		sprintf (matname,"%sm%i",filename,i);
		if (i<(obj->nummaterial-1)) fprintf (f,"ofs %s,",matname);
			else fprintf (f,"ofs %s         ; Material list\n",matname);
	}
	fprintf (f,"          dd        ");
	for (i=0;i<obj->numtexture;i++)
	{
		sprintf (matname,"%st%i",filename,i);
		if (i<(obj->nummaterial-1)) fprintf (f,"ofs %s,",matname);
			else fprintf (f,"ofs %s         ; texture list\n",matname);
	}

	fprintf (f,";---------------++-- Orgvertex --++-----------------\n");
	fprintf (f,"%s_sp");
	for (i=0;i<obj->numvertex;i++)
		fprintf (f,"    float %f,%f,%f\n",obj->orgvertex[i].x,obj->orgvertex[i].y,obj->orgvertex[i].z);

}
int v3o_save( char *filename, V3O *obj, int type)
{
	switch (type)
	{
		case V3O_SAVE_NORMAL : return v3o_save_normal (filename,obj); break;
		case V3O_SAVE_ASM : return v3o_save_asm (filename,obj); break;
		default : return FALSE;
	}
	return(FALSE);
}

void v3o_free( V3O *obj)
{
	int i;
	if( obj != NULL)
	{
		for( i=0; i<obj->numtexture; i++)
			vio_free( obj->texture[i].image);
		if( obj->texture != NULL) xfree( obj->texture);
		if( obj->material != NULL) xfree( obj->material);
		if( obj->surface != NULL) xfree( obj->surface);
		if( obj->orgvertex != NULL) xfree( obj->orgvertex);
		if( obj->rotvertex != NULL) xfree( obj->rotvertex);
		if( obj->projvertex != NULL) xfree( obj->projvertex);
		if( obj->orgnormal != NULL) xfree( obj->orgnormal);
		if( obj->rotnormal != NULL) xfree( obj->rotnormal);
		xfree( obj);
	}
}
/*####################################################################
	# Operational routines...
	# scale, calcboundingsphere, calcnormals, translate
	####################################################################*/
void v3o_translate (V3O *obj, float xf, float yf, float zf)
{
	int i;
	for (i=0;i<obj->numvertex;i++)
	{
		obj->orgvertex[i].x+=xf;
		obj->orgvertex[i].y+=yf;
		obj->orgvertex[i].z+=zf;
	}
}
void v3o_scale (V3O *obj, float xf, float yf, float zf)
{
	int i;
	for (i=0;i<obj->numvertex;i++)
	{
		obj->orgvertex[i].x*=xf;
		obj->orgvertex[i].y*=yf;
		obj->orgvertex[i].z*=zf;
	}
}
float v3o_boundingsphere (V3O *v3o)
{
	float l;
	int i;

	l=0;
	for (i=0;i<v3o->numvertex;i++)
		if (vector_length (&v3o->orgvertex[i])>l) l=vector_length(&v3o->orgvertex[i]);

	return l;
}
void v3o_calcnormals (V3O *obj)
{
	struct NM
	{
	  float x,y,z;
	  float c;
	} *pnormal;
 	VECTOR *vertex;
  V3OSURFACE *sf;
	VECTOR n,v1,v2;
  int pa,pb,pc;
  int i;

  vertex = obj->orgvertex;

  pnormal = (struct NM *)xsafe_malloc( obj->numvertex * sizeof(struct NM) );

  for( i=0; i<obj->numvertex; i++)
  {
    pnormal[i].c = 0;
    pnormal[i].x = 0;
    pnormal[i].y = 0;
    pnormal[i].z = 0;
  }
  for( i=0; i<obj->numsurface; i++)
  {
    sf = &obj->surface[i];

		pa = sf->v1;
    pb = sf->v2;
    pc = sf->v3;

    v1.x = vertex[pb].x - vertex[pa].x;
    v1.y = vertex[pb].y - vertex[pa].y;
    v1.z = vertex[pb].z - vertex[pa].z;

    v2.x = vertex[pc].x - vertex[pa].x;
    v2.y = vertex[pc].y - vertex[pa].y;
    v2.z = vertex[pc].z - vertex[pa].z;

		vector_crossprod (&v2,&v1,&n);

    pnormal[pa].x+=n.x;
    pnormal[pa].y+=n.y;
    pnormal[pa].z+=n.z;
    pnormal[pa].c++;

    pnormal[pb].x+=n.x;
    pnormal[pb].y+=n.y;
    pnormal[pb].z+=n.z;
    pnormal[pb].c++;

    pnormal[pc].x+=n.x;
    pnormal[pc].y+=n.y;
    pnormal[pc].z+=n.z;
    pnormal[pc].c++;
  }
  for( i=0; i<obj->numvertex; i++)
  {
    obj->orgnormal[i].x = pnormal[i].x/pnormal[i].c;
    obj->orgnormal[i].y = pnormal[i].y/pnormal[i].c;
    obj->orgnormal[i].z = pnormal[i].z/pnormal[i].c;
		vector_normalize (&obj->orgnormal[i]);
  }
  free (pnormal);
//  calc_radius (obj);

}
void v3o_center (V3O *obj)
{
  int i;
  float xmax,xmin,ymax,ymin,zmax,zmin;
  float xm,ym,zm;

  xmin=xmax=obj -> orgvertex[0].x;
  ymin=ymax=obj -> orgvertex[0].y;
  zmin=zmax=obj -> orgvertex[0].z;

// leta fram max och min...

  for (i=0;i<obj -> numvertex;i++)
  {
    if (obj -> orgvertex[i].x>xmax) xmax = obj -> orgvertex[i].x;
    if (obj -> orgvertex[i].y>ymax) ymax = obj -> orgvertex[i].y;
    if (obj -> orgvertex[i].z>zmax) zmax = obj -> orgvertex[i].z;
    if (obj -> orgvertex[i].x<xmin) xmin = obj -> orgvertex[i].x;
    if (obj -> orgvertex[i].y<ymin) ymin = obj -> orgvertex[i].y;
    if (obj -> orgvertex[i].z<zmin) zmin = obj -> orgvertex[i].z;
  }

// medelv„rde..

  xm = (xmax + xmin)*0.5;
  ym = (ymax + ymin)*0.5;
  zm = (zmax + zmin)*0.5;

//

  for (i=0;i<obj -> numvertex;i++)
  {
    obj -> orgvertex[i].x = obj -> orgvertex[i].x - xm;
    obj -> orgvertex[i].y = obj -> orgvertex[i].y - ym;
    obj -> orgvertex[i].z = obj -> orgvertex[i].z - zm;
  }
}

/*################################################################
	# v3o - geterror
	#################################################################*/
char *v3o_geterror(void)
{
	switch( error)
	{
		case ERR_NOERR: return( "[V3O] No error");
		case ERR_NOFILE: return( "[V3O] Unable to open file");
		case ERR_NOMEM: return( "[V3O] Unable to allocate memory");
    case ERR_NOTV3O: return( "[V3O] Not a V3O files");
    case ERR_WRONGVER: return( "[V3O] Wrong file version");
    case ERR_CUSTOM:
		{
			char str[256];
			strcpy( str, errstr);
			sprintf( errstr, "[V3O] %s", str);
			return( errstr);
		}
		default: return( "[V3O] Unknown error!");
	}
}
