⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lwreader.cpp

📁 赫赫大名的 OGRE 游戏引擎
💻 CPP
📖 第 1 页 / 共 4 页
字号:
#include "lwReader.h"

lwObject *lwReader::readObjectFromFile( const char *nfilename)
{
	lwObject *nobject = NULL;

	ifstream *ifs = new ifstream();
	try
	{
		ifs->open(nfilename, ios::in|ios::binary);
		if (ifs->fail())
			cout << "Could not open file: " << nfilename << endl;
		else
			nobject = readObjectFromStream( ifs );
	}
	catch (...)
	{
		if (nobject) delete nobject;
		nobject = NULL;
	}
	ifs->close();
	delete ifs;
	return nobject;
}

lwObject *lwReader::readObjectFromStream( istream *nis)
{
	lwObject *nobject = 0;
	chunksize = 0;
	currentchunkid = 0;
	formsize = 0;
	flen = 0;

	is = nis;

	try
	{
		long id = getU4();
		if ( id == ID_FORM )
		{
			formsize = getU4();
			long type = getU4();
			
			switch(type)
			{
			case ID_LWO2:
				nobject = lwGetLWO2(); // FORM0000LWXX -> filelength - 12
				break;
			case ID_LWOB:
			case ID_LWLO:
				nobject = lwGetLWLO(); // FORM0000LWXX -> filelength - 12
				break;
			default:
				throw "File does not contain Lightwave object.";
			}
		}
		else
			throw "Not an IFF FORM file.";
	}
	catch (char *errstr)
	{
		cout << "Error near byte " << is->tellg() << " in chunk " << currentchunkid << " : " << errstr << endl;
	}
	catch (...)
	{
		if (nobject) delete nobject;
		nobject = NULL;
	}
	return nobject;
}


lwObject *lwReader::lwGetLWLO()
{
	long filepos = is->tellg();
	if (filepos == -1) return NULL;
	long formstart = filepos;
	long formend = filepos + formsize; // FORM0000LWXX -> filelength - 12

	lwObject *object = new lwObject;
	if ( !object ) return NULL;

	lwLayer *layer = new lwLayer;
	if ( !layer ) goto Fail;

	lwSurface *surface;
	unsigned int rlen;
	unsigned long i;
	while ( filepos < formend )
	{
		currentchunkid = getU4();
		chunksize = getU4();
		chunksize += chunksize & 1;

		switch ( currentchunkid )
		{
		case ID_SRFS:
			if ( !lwGetTags(object->tags ))
				goto Fail;
			break;
		case ID_LAYR:
			if ( object->layers.size() > 0 )
			{
				layer = new lwLayer;
				if ( !layer ) goto Fail;
			}
			object->layers.push_back(layer);


			flen = 0;
			layer->index = getU2();
			layer->flags = getU2();
			layer->name = getS0();

			rlen = flen;
			if ( rlen < 0 || rlen > chunksize ) goto Fail;
			if ( rlen < chunksize )
				is->seekg(chunksize - rlen, ios_base::cur);
			break;
		case ID_PNTS:
			if ( !lwGetPoints(layer->points ))
				goto Fail;
			break;

		case ID_POLS:
			if ( !lwGetLWOBPolygons(layer->polygons, layer->pointsoffset ))
				goto Fail;
			break;

		case ID_SURF:
			surface = lwGetLWOBSurface(object );
			if ( surface ) object->surfaces.push_back( surface );
			break;

		case ID_SHCP:
		default:
			is->seekg(chunksize, ios_base::cur);
			break;
		}

		/* end of the file? */

		filepos = is->tellg();
		if ( filepos == -1 ) break;
		if ( filepos > formend ) break; // read too much
	}

	if ( object->layers.size() == 0 )
		object->layers.push_back(layer);

	for (i = 0; i < object->layers.size(); i++)
	{
		layer = object->layers[i];
		layer->lwGetBoundingBox();
		layer->lwResolveVertexPoints();
		layer->calculatePolygonNormals();
		layer->lwGetPointPolygons();

		if ( !layer->lwResolvePolySurfaces(object->surfaces, object->tags)) goto Fail;
		layer->calculateVertexNormals();
	}

	return object;
Fail:
	if (object) delete object;
	return NULL;
}

lwObject *lwReader::lwGetLWO2()
{
	long filepos = is->tellg();
	if (filepos == -1) return NULL;
	long formstart = filepos;
	long formend = filepos + formsize; // FORM0000LWXX -> filelength - 12

	/* allocate an object and a default layer */

	lwObject *object = new lwObject;
	if ( !object ) return NULL;

	lwLayer *layer = new lwLayer;
	if ( !layer ) goto Fail;

	unsigned int i, rlen;

	lwVMap *vmap;
	lwEnvelope *envelope;
	lwClip *clip;
	lwSurface *surface;

	/* process chunks as they're encountered */

	while ( filepos < formend )
	{
		currentchunkid = getU4();
		chunksize = getU4();
		chunksize += chunksize & 1;

		switch ( currentchunkid )
		{
		case ID_LAYR:
			if ( object->layers.size() > 0 )
			{
				layer = new lwLayer;
				if ( !layer ) goto Fail;
			}
			object->layers.push_back(layer);

			flen = 0;
			layer->index = getU2();
			layer->flags = getU2();
			layer->pivot.x = getF4();
			layer->pivot.y = getF4();
			layer->pivot.z = getF4();
			layer->name = getS0();

			rlen = flen;
			if ( rlen < 0 || rlen > chunksize ) goto Fail;
			if ( rlen <= chunksize - 2 )
				layer->parent = getU2();
			rlen = flen;
			if ( rlen < chunksize )
				is->seekg(chunksize - rlen, ios_base::cur);
			break;

		case ID_PNTS:
			if ( !lwGetPoints(layer->points ))
				goto Fail;
			break;

		case ID_POLS:
			if ( !lwGetPolygons(layer->polygons, layer->pointsoffset ))
				goto Fail;
			break;

		case ID_VMAP:
		case ID_VMAD:
			vmap = lwGetVMap(layer->pointsoffset, layer->polygonsoffset, currentchunkid == ID_VMAD );
			if ( !vmap ) goto Fail;
			layer->vmaps.push_back(vmap);
			break;

		case ID_PTAG:
			if ( !lwGetPolygonTags(object->tags, object->tagsoffset, layer->polygons, layer->polygonsoffset ))
				goto Fail;
			break;

		case ID_BBOX:
			flen = 0;
			layer->bboxmin.x = getF4();
			layer->bboxmin.y = getF4();
			layer->bboxmin.z = getF4();
			layer->bboxmax.x = getF4();
			layer->bboxmax.y = getF4();
			layer->bboxmax.z = getF4();
			rlen = flen;
			if ( rlen < 0 || rlen > chunksize ) goto Fail;
			if ( rlen < chunksize )
				is->seekg(chunksize - rlen, ios_base::cur );
			break;

		case ID_TAGS:
			if ( !lwGetTags(object->tags ))
				goto Fail;
			break;

		case ID_ENVL:
			envelope = lwGetEnvelope();
			if ( !envelope ) goto Fail;
			object->envelopes.push_back( envelope );
			break;

		case ID_CLIP:
			clip = lwGetClip();
			if ( !clip ) goto Fail;
			object->clips.push_back( clip );
			break;

		case ID_SURF:
			surface = lwGetSurface();
			if ( !surface ) goto Fail;
			object->surfaces.push_back( surface );
			break;

		case ID_DESC:
		case ID_TEXT:
		case ID_ICON:
		default:
			is->seekg(chunksize, ios_base::cur );
			break;
		}

		/* end of the file? */
		filepos = is->tellg();
		if ( filepos == -1 ) break;
		if ( filepos > formend ) break; // read too much
	}
	
	if ( object->layers.size() == 0 )
		object->layers.push_back(layer);
				
	for (i = 0; i < object->layers.size(); i++)
	{
		layer = object->layers[i];
		if ( !layer->lwResolvePolySurfaces(object->surfaces, object->tags)) goto Fail;

		layer->lwGetBoundingBox();
		layer->lwResolveVertexPoints();
		layer->calculatePolygonNormals();
		layer->lwGetPointPolygons();
		layer->calculateVertexNormals();
		layer->lwGetPointVMaps();
		layer->lwGetPolyVMaps();
	}

	return object;
Fail:
	if(object) delete object;
	return NULL;
}

#define FLEN_ERROR INT_MIN

#ifdef _WIN32
/*
=====================================================================
revbytes()

Reverses byte order in place.
 
INPUTS
bp		 bytes to reverse
elsize	size of the underlying data type
elcount  number of elements to swap

RESULTS
Reverses the byte order in each of elcount elements.

This only needs to be defined on little-endian platforms, most
notably Windows.  lwo2.h replaces this with a #define on big-endian
platforms.
===================================================================== */

unsigned short lwReader::swappedShort(unsigned short w)
{
	unsigned short tmp;
	tmp =  (w & 0x00ff);
	tmp = ((w & 0xff00) >> 0x08) | (tmp << 0x08);
	return tmp;
}

unsigned long lwReader::swappedLong(unsigned long w)
{
	unsigned long tmp;
	tmp =  (w & 0x000000ff);
	tmp = ((w & 0x0000ff00) >> 0x08) | (tmp << 0x08);
	tmp = ((w & 0x00ff0000) >> 0x10) | (tmp << 0x08);
	tmp = ((w & 0xff000000) >> 0x18) | (tmp << 0x08);
	return tmp;
}

void lwReader::revbytes( void *bp, int elsize, int elcount )
{
	register char *p, *q;
	
	p = ( char * ) bp;
	
	if ( elsize == 2 ) {
		q = p + 1;
		while ( elcount-- ) {
			*p ^= *q;
			*q ^= *p;
			*p ^= *q;
			p += 2;
			q += 2;
		}
		return;
	}
	
	while ( elcount-- ) {
		q = p + elsize - 1;
		while ( p < q ) {
			*p ^= *q;
			*q ^= *p;
			*p ^= *q;
			++p;
			--q;
		}
		p += elsize >> 1;
	}
}
#endif

char *lwReader::getbytes( int size )
{
	char *data;
	
	if ( flen == FLEN_ERROR ) return NULL;
	if ( size < 0 ) {
		flen = FLEN_ERROR;
		return NULL;
	}
	if ( size == 0 ) return NULL;

	data = (char*)malloc(size);

	if ( !data )
	{
		flen = FLEN_ERROR;
		return NULL;
	}
	
	is->read((char *)data, size);
	if (is->gcount() != size)
	{
		flen = FLEN_ERROR;
		free (data);
		return NULL;
	}
	
	flen += size;
	return data;
}


void lwReader::skipbytes( int n )
{
	if ( flen == FLEN_ERROR ) return;
	
	is->seekg(n, ios_base::cur);
	
	if (is->bad())
		flen = FLEN_ERROR;
	else
		flen += n;
}

short lwReader::getI2()
{
	short i;
	
	if ( flen == FLEN_ERROR ) return 0;
	
	is->read((char *)&i, 2);
	if (is->gcount() != 2)
	{
		flen = FLEN_ERROR;
		return 0;
	}
	revbytes( &i, 2, 1 );
	flen += 2;
	return i;
}


long lwReader::getI4()
{
	long i;
	
	if ( flen == FLEN_ERROR ) return 0;
	
	is->read((char *)&i, 4);
	if (is->gcount() != 4) {
		flen = FLEN_ERROR;
		return 0;
	}
	revbytes( &i, 4, 1 );
	flen += 4;
	return i;
}


unsigned char lwReader::getU1()
{
	unsigned char i;
	
	if ( flen == FLEN_ERROR ) return 0;
	is->read((char *)&i, 1);
	if (is->gcount() != 1)
	{
		flen = FLEN_ERROR;
		return 0;
	}
	flen += 1;
	return i;
}


unsigned short lwReader::getU2()
{
	unsigned short i;
	
	if ( flen == FLEN_ERROR ) return 0;
	is->read((char *)&i, 2);
	if (is->gcount() != 2)
	{
		flen = FLEN_ERROR;
		return 0;
	}
	revbytes( &i, 2, 1 );
	flen += 2;
	return i;
}


unsigned long lwReader::getU4()
{
	unsigned long i;
	
	if ( flen == FLEN_ERROR ) return 0;
	is->read((char *)&i, 4);
	if (is->gcount() != 4)
	{
		flen = FLEN_ERROR;
		return 0;
	}
	revbytes( &i, 4, 1 );
	flen += 4;
	return i;
}


int lwReader::getVX()
{
	int i;
	short c;
	
	if ( flen == FLEN_ERROR ) return 0;
	
	is->read((char *)&c, 2);
	
	if ( (c & 0x00FF) != 0xFF )
	{
		i = swappedShort(c);
		flen += 2;
	}
	else
	{
		i = (swappedShort(c) & 0x00FF) << 16;
		is->read((char *)&c, 2);
		i |= swappedShort(c);
		flen += 4;
	}
	
	if ( is->bad() ) {
		flen = FLEN_ERROR;
		return 0;
	}
	return i;
}


float lwReader::getF4()
{
	float f;
	
	if ( flen == FLEN_ERROR ) return 0.0f;
	is->read((char *)&f, 4);
	if (is->gcount() != 4)
	{
		flen = FLEN_ERROR;
		return 0.0f;
	}
	revbytes( &f, 4, 1 );
	flen += 4;
	return f;
}

char *lwReader::getS0()
{
	char *s;
	int i, len, pos;
	char c;

	if ( flen == FLEN_ERROR ) return NULL;

	pos = is->tellg();
	if (pos == -1) return 0;

	i = 0;
	do
	{
		is->read(&c, 1);
		i ++;
	}
	while (c > 0);

	if ( i == 1 ) // word align
	{
		is->read(&c, 1);
		flen += 2;
		return NULL;
	}

	len = i + ( i & 1 );

	s = (char *)malloc(len);
	if ( !s )
	{
		flen = FLEN_ERROR;
		return NULL;
	}

	is->seekg(pos, ios_base::beg);
	if (is->bad())
	{
		flen = FLEN_ERROR;
		return NULL;
	}

	is->read(s, len);
	if (is->gcount() != len)
	{
		flen = FLEN_ERROR;
		return NULL;
	}
	
	flen += len;
	return s;
}

short lwReader::sgetI2( char **bp )
{
	short i;
	
	if ( flen == FLEN_ERROR ) return 0;
	memcpy( &i, *bp, 2 );
	revbytes( &i, 2, 1 );
	flen += 2;
	*bp += 2;
	return i;
}


long lwReader::sgetI4( char **bp )
{
	long i;
	
	if ( flen == FLEN_ERROR ) return 0;
	memcpy( &i, *bp, 4 );
	revbytes( &i, 4, 1 );
	flen += 4;
	*bp += 4;
	return i;
}


unsigned char lwReader::sgetU1( char **bp )
{
	unsigned char c;
	
	if ( flen == FLEN_ERROR ) return 0;
	c = **bp;
	flen += 1;
	*bp++;
	return c;
}

unsigned short lwReader::sgetU2(char **bp )
{
	unsigned char *buf = (unsigned char *)*bp;
	unsigned short i;
	
	if ( flen == FLEN_ERROR ) return 0;
	i = ( buf[ 0 ] << 8 ) | buf[ 1 ];
	flen += 2;
	*bp += 2;
	return i;
}

unsigned long lwReader::sgetU4( char **bp )
{
	unsigned long i;
	
	if ( flen == FLEN_ERROR ) return 0;
	memcpy( &i, *bp, 4 );
	revbytes( &i, 4, 1 );
	flen += 4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -