/////////////////////////////////////////////////////////////////////////////////////
//Project:	LWO2 Loader Prototype
//Author:	Antonio Lattanzio	-	D3stY
//e-mail:	D3stY@softhome.net
//Date:		13/06/00
//Notes:	This piece of code demonstrates how we can handle Lightwave 6 Objects (LWO2).
/////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
#include "3dtypes.h"
#include "useful.h"
  //Some Inverted Tags x IFF format
#define LWO2_FORM 'MROF'	//FROM
#define LWO2_LWO2 '2OWL'	//LWO2
#define LWO2_TAGS 'SGAT'	//TAGS
#define LWO2_LAYR 'RYAL'	//LAYR
#define LWO2_PNTS 'STNP'	//PNTS
#define	LWO2_POLS 'SLOP'	//POLS
#define	LWO2_FACE 'ECAF'	//FACE
#define	LWO2_VMAP 'PAMV'	//VMAP
#define	LWO2_TXUV 'VUXT'	//TXUV
#define	LWO2_SURF 'FRUS'	//SURF
#define LWO2_WGHT 'THGW'	//WGHT
#define LWO2_PTAG 'GATP'	//PTAG
long GetChunk(char* buffer,t_object *o);
  //invert 4 bytes and returns a long
void invert4bytes( char *src , char *res )
{
	BYTE x=3,y=0;
	while (y!=4) res[y++] = src[x--];
}
  // LoadLWO2
BOOL LoadLWO2( char* filename, t_object *g_obj )
{
    char*       memfile	= NULL;
    int         flength	= 0;
    bool        loaded	= false;
  	if (filename==NULL) return false;
	memset(g_obj,0,sizeof(g_obj));
	FILE		*file = fopen(filename,"rb");
	if (!file)	return FALSE;
  	fseek(file,0,SEEK_END);
	flength = ftell(file);
	memfile = new char[flength];
	rewind(file);
	fread(memfile, 1,flength,file);
	fclose(file);
  	//MessageBox(NULL,filename,"",MB_OK);
	GetChunk(memfile,g_obj);// start recursive parsing
	delete memfile;
  	if (g_obj->numpolys==0||g_obj->numverts==0) return false;
	return TRUE;
  }
  long GetChunk(char* buffer,t_object *g_obj)
{
	long	chunkid = *(long*)(buffer);
    long	chunklength;
  	static t_mesh *c_mesh=NULL;
	static t_uvmap	*c_uvmap=NULL;
	static t_wmap	*c_wmap=NULL;
	static t_plist	*c_plist=NULL;
	static t_surf	*c_surf=NULL;
  	invert4bytes( buffer+4, (char*)&chunklength );
      int		i = 8;
    int		j;
      switch (chunkid)
    {
    case LWO2_FORM:
		{
			char str[255];
			memset(str,0,255);
			int x=0;
			while (x<4) {str[x]=buffer[i++];x++;}
			if (strcmp(str,"LWO2")!=0) 
			{
				MessageBox(NULL,"Wrong File Format!","Whassuuup??",MB_OK);
				i=chunklength;
			}
			break;
		}
    case LWO2_PNTS: //get all points
		{
			//First Mesh Entry
			if (g_obj->meshes==NULL) {
				c_mesh = g_obj->meshes = new t_mesh;
				memset(c_mesh,0,sizeof(t_mesh));
				g_obj->nummeshes++;
			}else{
				t_mesh *tm=g_obj->meshes;
				while (tm->next) tm=tm->next;
				c_mesh = new t_mesh;
				memset(c_mesh,0,sizeof(t_mesh));
				tm->next = c_mesh;
				tm->next->prev = tm;
				g_obj->nummeshes++;
			}
  			if (c_mesh->numverts == NULL)
			{
				c_mesh->numverts = chunklength/12;
				c_mesh->verts	= new t_vert3[c_mesh->numverts];
				for (j=0;j<c_mesh->numverts;j++)
				{
					invert4bytes( buffer+i, (char*)&c_mesh->verts[j].x );i+=4;
					invert4bytes( buffer+i, (char*)&c_mesh->verts[j].y );i+=4;
					invert4bytes( buffer+i, (char*)&c_mesh->verts[j].z );i+=4;
				}
				g_obj->numverts+=c_mesh->numverts;
  				//char str[255];
				//sprintf(str,"Mesh: %u\tVerts:%u\n",g_obj->nummeshes,c_mesh->numverts);
				//OutputDebugString(str);
			} else	i = chunklength;
			break;
		}
		
    case LWO2_POLS: //get all polys
		{
			if (*(long*)(buffer+i)==LWO2_FACE)
			if (c_mesh->polys == NULL)
			{
				c_mesh->numpolys = 0;
				i+=4;
  				//chunklength+=8;
				for (j=i;j<=chunklength;)
				{
					short vnum = *(char*)(buffer+j+1) + (*(char*)(buffer+j)<<8);
					j+=2+vnum*2;
					c_mesh->numpolys++;
					if (vnum!=3) {
						//delete (c_mesh->polys);
						//c_mesh->polys=NULL;
						//delete (c_mesh);
						//delete (c_mesh->verts);
						//g_obj->nummeshes--;
						MessageBox(NULL,"Yo.. Check Geometry! [3verts x poly]","WASSSUUUPPP!!!",MB_OK);
						i=chunklength;
						break;
					}
				}
				//if (j!=chunklength) break;
				c_mesh->polys = new t_poly[c_mesh->numpolys];
				int p=0;
				for (j=i;j<=chunklength;)
				{
					short vnum = *(char*)(buffer+j+1) + (*(char*)(buffer+j)<<8);j+=2;
					c_mesh->polys[p].verts[0] = (BYTE)buffer[j+1] + ((BYTE)buffer[j]<<8);j+=2;
					c_mesh->polys[p].verts[1] = (BYTE)buffer[j+1] + ((BYTE)buffer[j]<<8);j+=2;
					c_mesh->polys[p].verts[2] = (BYTE)buffer[j+1] + ((BYTE)buffer[j]<<8);j+=2;
					p++;
				}
				i=chunklength;
				g_obj->numpolys+=c_mesh->numpolys;
			} else	i = chunklength;
			break;
		}
  	case LWO2_VMAP:
		{
			int j=0;
			UINT vmode = *(long*)(buffer+i);
  			if ( vmode==LWO2_TXUV||vmode==LWO2_WGHT )
			{
				j+=4;
				short entries = *(char*)(buffer+i+j+1) + (*(char*)(buffer+i+j)<<8);
				j+=2;
				UINT strlen=0;
				while (buffer[i+j]!=0) {j++;strlen++;}
				if (strlen%2!=0) j++;else j+=2;
  				int tot = (chunklength-j)/(entries*4+2);
				//char str[255];
				//sprintf(str,"%u - %u - %f",entries,chunklength-j,(float)(chunklength-j)/(entries*4+2));
				//MessageBox(NULL,str,"",MB_OK);
				int vnum=0;
  				if (vmode==LWO2_TXUV)
				{
					if (g_obj->uvmap==NULL) {
						c_uvmap = g_obj->uvmap = new t_uvmap;
						memset(c_uvmap,0,sizeof(t_uvmap));
						g_obj->numuvmaps++;
					}else{
						t_uvmap *tuv=g_obj->uvmap;
						while (tuv->next) tuv=tuv->next;
						c_uvmap = new t_uvmap;
						memset(c_uvmap,0,sizeof(t_uvmap));
						tuv->next = c_uvmap;
						tuv->next->prev = tuv;
						g_obj->numuvmaps++;
					}
  					c_uvmap->name = new char[strlen+1];
					strcpy(c_uvmap->name,buffer+i+6);
					c_uvmap->u = new float[tot];
					c_uvmap->v = new float[tot];
					c_uvmap->index = new UINT[tot];
  					while (j<chunklength)
					{
						float u=0,v=0;
						BYTE v1 = *(char*)(buffer+i+j+1);
						BYTE v2 = *(char*)(buffer+i+j);
  						unsigned short vert = v1+v2*0xff;j+=2;//*(char*)(buffer+i+j+1) + (*(char*)(buffer+i+j)<<8);j+=2;
						invert4bytes( buffer+i+j, (char*)&u );j+=4;
						invert4bytes( buffer+i+j, (char*)&v );j+=4;
  						c_uvmap->u[vnum] = u;
						c_uvmap->v[vnum] = v;
						c_uvmap->index[vnum] = vert;
						vnum++;
					}
					char str[255];
					sprintf(str,"Mesh: %u\tUVs:%u/%u\n",g_obj->nummeshes,vnum,tot);
					OutputDebugString(str);
				}else
				if (vmode==LWO2_WGHT)
				{
					if (g_obj->wmap==NULL) {
						c_wmap = g_obj->wmap = new t_wmap;
						memset(c_wmap,0,sizeof(t_wmap));
						g_obj->numwmaps++;
					}else{
						t_wmap *tw=g_obj->wmap;
						while (tw->next) tw=tw->next;
						c_wmap = new t_wmap;
						memset(c_wmap,0,sizeof(t_wmap));
						tw->next = c_wmap;
						tw->next->prev = tw;
						g_obj->numwmaps++;
					}
  					c_wmap->name = new char[strlen+1];
					strcpy(c_wmap->name,buffer+i+6);
					c_wmap->w = new float[tot];
					c_wmap->index = new UINT[tot];
  					while (j<chunklength)
					{
						float power=0;
						BYTE v1 = *(char*)(buffer+i+j+1);
						BYTE v2 = *(char*)(buffer+i+j);
						unsigned short vert = v1+v2*0xff;j+=2;
						invert4bytes( buffer+i+j, (char*)&power );j+=4;
  						c_wmap->w[vnum] = power;
						c_wmap->index[vnum] = vert;
						vnum++;
  						//char str[255];
						//sprintf(str,"Mesh: %u\tVert:%u\tW:%f\n",g_obj->nummeshes,vert,power);
						//OutputDebugString(str);
					}
					char str[255];
					sprintf(str,"Mesh: %u\tWs:%u/%u\n",g_obj->nummeshes,vnum,tot);
					OutputDebugString(str);
				}
			}
  			i = chunklength;
			break;
		}
  	case LWO2_SURF:
		{
			UINT j=0;
			UINT strlen=0;
			while (buffer[i+j]!=0) {j++;strlen++;}
			if (strlen%2!=0) j++;else j+=2;
			//MessageBox(NULL,buffer+i,"",MB_OK);
			if (g_obj->surf==NULL) {
				c_surf = g_obj->surf = new t_surf;
				memset(c_surf,0,sizeof(t_surf));
				g_obj->numsurfs++;
			}else{
				t_surf *ts=g_obj->surf;
				while (ts->next) ts=ts->next;
				c_surf = new t_surf;
				memset(c_surf,0,sizeof(t_surf));
				ts->next = c_surf;
				ts->next->prev = ts;
				g_obj->numsurfs++;
			}
  			c_surf->name = new char[strlen+1];
			strcpy(c_surf->name,buffer+i);
			//MessageBox(NULL,c_surf->name,"",MB_OK);
			i = chunklength;
  			break;
		}
  	case LWO2_PTAG:
		{
			int j=4;
			UINT vmode = *(long*)(buffer+i);
			if (vmode==LWO2_SURF)
			{
				UINT plnum = (chunklength-4)/4;
				char str[255];
				sprintf(str,"PTags: %u - %u\n",chunklength-4,(chunklength-4)/4);
				OutputDebugString(str);
  				if (g_obj->plist==NULL) {
					c_plist = g_obj->plist = new t_plist;
					memset(c_plist,0,sizeof(t_plist));
					g_obj->numplists++;
				}else{
					t_plist *tpl=g_obj->plist;
					while (tpl->next) tpl=tpl->next;
					c_plist = new t_plist;
					memset(c_plist,0,sizeof(t_plist));
					tpl->next = c_plist;
					tpl->next->prev = tpl;
					g_obj->numplists++;
				}
  				c_plist->list = new UINT[plnum];
  				UINT vnum=0;
				while (j<chunklength)
				{
					short val = (short)(((BYTE)buffer[i+j])+(BYTE)buffer[i+j+1]);j+=2;
					short sur = (short)(((BYTE)buffer[i+j])+(BYTE)buffer[i+j+1]);j+=2;
  					//invert4bytes( buffer+i+j, (char*)&val );j+=4;
					
					c_plist->list[vnum++] = val;
					//char str[255];
					//sprintf(str,"Pv: %u/%u\n",val,sur);
					//OutputDebugString(str);
				}
  			}
			i = chunklength;
			break;
		}
      default:
        i = chunklength;    // ignoring other chunks ... we can easly add more code here!
        break;
    }
      while (i < chunklength) i += GetChunk(buffer+i,g_obj)+8;
    return chunklength;
}
   |