void LWOReader::ReadPTAG( UInt32 pChunkSize ) { UInt32 dataRead = 0; LWIndex index; LWIndex val; UInt32 tagType; dataRead += ReadID4( tagType ); if( tagType != ID_SURF && tagType != ID_PART && tagType != ID_SMGP ) { Skip( pChunkSize - dataRead ); return; } while( dataRead < pChunkSize ) { dataRead += ReadVX( index ); dataRead += ReadVX( val ); switch( tagType ) { case ID_SURF: GetCurrentLayer()->mPolygonList.mPolygons[index]->mSurfaceIndex = val; break; case ID_PART: GetCurrentLayer()->mPolygonList.mPolygons[index]->mPartIndex = val; break; case ID_SMGP: GetCurrentLayer()->mPolygonList.mPolygons[index]->mSmoothingGroupIndex = val; break; } } }
bool LWOFile::LoadVMAP(unsigned int iChunkSize) { Layer *pLayer=GetLastLayer(); if(pLayer==NULL) { AddError("No LAYR before VMAP"); return false; } // VMAP { type[ID4], dimension[U2], name[S0], // ( vert[VX], value[F4] # dimension )* } unsigned int iType=0; if(!ReadID4(iType)) { return false; } // uvmap if(iType==ID4("TXUV")) { return LoadUVMap(iChunkSize); } // weightmap else if(iType==ID4("WGHT")) { return LoadWeightMap(iChunkSize); } // unknown type - skip m_pData+=iChunkSize-4; AddError("Warning: Unknown vertex map type "+ID4ToString(iType)); return true; }
bool LWOFile::LoadPOLS(unsigned int iChunkSize) { Layer *pLayer=GetLastLayer(); if(pLayer==NULL) { AddError("No LAYR before POLS"); return false; } const char *pChunkEndPos=m_pData+iChunkSize; // POLS { type[ID4], ( numvert+flags[U2], vert[VX] # numvert )* } unsigned int iType=0; if(!ReadID4(iType)) return false; // only faces supported (but patches control cage can be loaded as well) if(iType!=ID4("FACE") && iType!=ID4("PTCH")) { AddError("Warning: POLS has unsupported type "+ID4ToString(iType)); // skip m_pData=pChunkEndPos; return true; } unsigned int iBytesLeft=iChunkSize-4; // allocate for worst case polygon count unsigned int iPolysNeeded=iBytesLeft/(2+2); unsigned int iExistingPolys=(unsigned int)pLayer->m_Polygons.size(); pLayer->m_Polygons.resize(iExistingPolys+iPolysNeeded); unsigned int iPolygon=0; while(m_pData<pChunkEndPos) { // read vertex count unsigned short iVertexCount; if(!ReadU2(iVertexCount)) return false; // quote: The 6 high-order bits of the vertex count are flag // bits with different meanings for each polygon type. // // let's just mask them out iVertexCount &= 0x03FF; pLayer->m_Polygons[iExistingPolys+iPolygon].m_iSurface=0xffff; pLayer->m_Polygons[iExistingPolys+iPolygon].m_Vertices.resize(iVertexCount); unsigned int *pVertices=&pLayer->m_Polygons[iExistingPolys+iPolygon].m_Vertices[0]; for(unsigned short j=0;j<iVertexCount;j++) { if(!ReadVX(pVertices[j])) return false; } iPolygon++; } // make array size match the actual polygon count pLayer->m_Polygons.resize(iExistingPolys+iPolygon); return true; }
void LWOReader::ReadPOLS( UInt32 pChunkSize ) { UInt32 dataRead = 0; UInt16 numVertex; UInt32 polygonType; LWPolygon* newPolygon; dataRead += ReadID4( polygonType ); while( dataRead < pChunkSize ) { newPolygon = GD_NEW(LWPolygon, this, "Polygon"); dataRead += ReadU2( numVertex ); newPolygon->mFlags = (0xFC00 & numVertex) >> 10; numVertex = 0x03FF & numVertex; newPolygon->mType = polygonType; newPolygon->mVertex = GD_NEW_ARRAY(LWPolygonVertex, numVertex, this, "Polygon::Vertex"); newPolygon->mVertexCount = numVertex; // Read indices and assign them to each vertex for( UInt32 iIndex = 0; iIndex < newPolygon->mVertexCount; iIndex++ ) dataRead += ReadVX( newPolygon->mVertex[iIndex].mIndex ); GetCurrentLayer()->mPolygonList.mPolygons.push_back( newPolygon ); } }
bool LWOFile::LoadSURF(unsigned int iChunkSize) { Surface surf; surf.m_vBaseColor[0] = 1.0f; surf.m_vBaseColor[1] = 1.0f; surf.m_vBaseColor[2] = 1.0f; // SURF { name[S0], source[S0], attributes[SUB-CHUNK] * } const char *pChunkEndPos=m_pData+iChunkSize; // name unsigned int iStrBytes=0; if(!ReadS0(surf.m_strName,iStrBytes)) { return false; } // source if(!ReadS0(surf.m_strSource,iStrBytes)) { return false; } // while there's data left while(m_pData<pChunkEndPos) { // get chunk ID unsigned int iID=0; if(!ReadID4(iID)) return false; // get chunk size unsigned short iChunkSize=0; if(!ReadU2(iChunkSize)) return false; const char *pSubChunkEndPos=m_pData+iChunkSize; // color if(iID == ID4("COLR")) { // COLR { base-color[COL12], envelope[VX] } // read values if(!ReadF4(surf.m_vBaseColor[0])) return false; if(!ReadF4(surf.m_vBaseColor[1])) return false; if(!ReadF4(surf.m_vBaseColor[2])) return false; } // skip to end of sub-chunk m_pData = pSubChunkEndPos; if(iChunkSize%2==1) m_pData+=1; } m_Surfaces.push_back(surf); return true; }
bool LWOFile::LoadPTAG(unsigned int iChunkSize) { Layer *pLayer=GetLastLayer(); if(pLayer==NULL) { AddError("No LAYR before PTAG"); return false; } if(pLayer->m_Polygons.size()==0) { AddError("No POLS before PTAG"); return false; } const char *pChunkEndPos=m_pData+iChunkSize; // read type unsigned int iType=0; if(!ReadID4(iType)) { return false; } if(iType!=ID4("SURF")) { // unknown type - skip m_pData+=iChunkSize-4; AddError("Warning: Unknown PTAG type "+ID4ToString(iType)); return true; } while(m_pData<pChunkEndPos) { // read poly id unsigned int iPolyID; if(!ReadVX(iPolyID)) return false; // read tag unsigned short iTag; if(!ReadU2(iTag)) return false; if(iPolyID>=pLayer->m_Polygons.size()) return false; pLayer->m_Polygons[iPolyID].m_iSurface=iTag; } return true; }
void LWOReader::ReadHEAD( LWSurfaceBlock* pSurfaceBlock, UInt32 pChunkSize ) { UInt32 dataRead = 0; UInt16 subChunkSize; UInt32 subChunkTag; UInt32 bytesHold; LWIndex env; dataRead += ReadS0( pSurfaceBlock->mOrdinalString ); while( dataRead < pChunkSize ) { subChunkTag = ReadSubChunk(subChunkSize,2); dataRead += sizeof(subChunkTag); // Subchunk tag. dataRead += sizeof(subChunkSize); // Subchunk size. bytesHold = dataRead; switch( subChunkTag ) { case ID_CHAN: dataRead += ReadID4( pSurfaceBlock->mTextureChannel ); break; case ID_ENAB: dataRead += ReadU2( pSurfaceBlock->mEnableState ); break; case ID_OPAC: dataRead += ReadU2( pSurfaceBlock->mOpacityType ); dataRead += ReadFP4( pSurfaceBlock->mOpacity ); dataRead += ReadVX( env ); break; default: dataRead += Skip( subChunkSize ); break; } // Make sure we've read all subchunk bytes (given by the size). if( (subChunkSize - dataRead + bytesHold) > 0 ) dataRead += Skip( subChunkSize - dataRead + bytesHold ); } }
bool LWOFile::LoadVMAD(unsigned int iChunkSize) { Layer *pLayer=GetLastLayer(); if(pLayer==NULL) { AddError("No LAYR before VMAD"); return false; } const char *pChunkEndPos=m_pData+iChunkSize; // VMAD { type[ID4], dimension[U2], name[S0], // ( vert[VX], poly[VX], value[F4] # dimension )* } unsigned int iType=0; if(!ReadID4(iType)) return false; // type must be uvmap if(iType!=ID4("TXUV")) { AddError("Warning: Unknown discontinuous vertex map type "+ID4ToString(iType)); m_pData+=iChunkSize-4; return true; } // dimension unsigned short iDimension=0; if(!ReadU2(iDimension)) { return false; } // not 2 floats per vertex if(iDimension!=2) { AddError("Warning: Discontinuous UVMap has "+ConvertToString(iDimension)+" floats per vertex (2 expected)"); // skip m_pData+=iChunkSize-4-2; return true; } // name unsigned int iStrBytes=0; std::string strName; if(!ReadS0(strName,iStrBytes)) { return false; } // for each uvmap UVMap *pUV=NULL; for(unsigned int iUV=0;iUV<pLayer->m_UVMaps.size();iUV++) { if(pLayer->m_UVMaps[iUV]->m_strName==strName) { pUV=pLayer->m_UVMaps[iUV]; } } if(pUV==NULL) { AddError("No matching UVMap for discontinuous UVMap \""+strName+"\""); return false; } // read rest of chunk to memory // unsigned int iBytesLeft=iChunkSize-4-2-iStrBytes; UVMapD *pUVMap=new UVMapD(); pUVMap->m_strName=strName; pUVMap->m_pUVMap=pUV; // worst case estimate pUVMap->m_Entries.reserve(iBytesLeft/(2+2+4+4)); pLayer->m_UVMapDs.push_back(pUVMap); while(m_pData<pChunkEndPos) { unsigned int iVertexID=0; if(!ReadVX(iVertexID)) return false; unsigned int iPolyID=0; if(!ReadVX(iPolyID)) return false; UVMapD::Entry e; e.iVertex=iVertexID; e.iPolygon=iPolyID; if(!ReadF4(e.u)) return false; if(!ReadF4(e.v)) return false; // flip v coordinate e.v=1-e.v; pUVMap->m_Entries.push_back(e); } return true; }
bool LWOFile::LoadFromMemory(const void *pData, unsigned int iFileSize) { if(pData==NULL || iFileSize==0) { AddError("Loading from memory failed: no data"); return false; } m_pData=(const char*)pData; m_pDataEnd=m_pData+iFileSize; // read main chunk id // unsigned int iID=0; if(!ReadID4(iID) || iID!=ID4("FORM")) { AddError("Main chunk FORM not found!"); return false; } // read main chunk size // unsigned int iMainSize=0; if(!ReadU4(iMainSize)) return false; // read file format // if(!ReadID4(iID)) return false; if(iID!=ID4("LWO2")) { AddError("Format "+ID4ToString(iID)+" is not supported!"); return false; } unsigned int iLayerID=ID4("LAYR"); unsigned int iPointsID=ID4("PNTS"); unsigned int iPolygonsID=ID4("POLS"); unsigned int iVertexMapID=ID4("VMAP"); unsigned int iVertexMapDID=ID4("VMAD"); unsigned int iTagsID=ID4("TAGS"); unsigned int iPTagsID=ID4("PTAG"); unsigned int iSurfID=ID4("SURF"); // while we have data left // while(m_pData<m_pDataEnd) { // get chunk ID // unsigned int iID=0; if(!ReadID4(iID)) return false; // get chunk size // unsigned int iChunkSize=0; if(!ReadU4(iChunkSize)) return false; // attempt to load chunk // LAYR /////////////////// if(iID==iLayerID) { if(!LoadLAYR(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // PNTS /////////////////// else if(iID==iPointsID) { if(!LoadPNTS(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // POLS /////////////////// else if(iID==iPolygonsID) { if(!LoadPOLS(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // VMAP /////////////////// else if(iID==iVertexMapID) { if(!LoadVMAP(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // VMAD /////////////////// else if(iID==iVertexMapDID) { if(!LoadVMAD(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // TAGS /////////////////// else if(iID==iTagsID) { if(!LoadTAGS(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // PTAG /////////////////// else if(iID==iPTagsID) { if(!LoadPTAG(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // SURF /////////////////// else if(iID==iSurfID) { if(!LoadSURF(iChunkSize)) { AddError("Loading chunk "+ID4ToString(iID)+" failed!"); return false; } } // unknown /////////////////// else { AddError("Warning: Unknown chunk ID "+ID4ToString(iID)); m_pData+=iChunkSize; } // quote: If the chunk size is odd, the chunk is followed by a 0 pad byte, // so that the next chunk begins on an even byte boundary. if(iChunkSize%2==1) m_pData+=1; } m_pData=NULL; m_pDataEnd=NULL; return true; }
void LWOReader::Read( const String& pFilename, LWObject& pObject ) { UInt32 dataSize = 0; UInt32 dataRead = 0; UInt32 chunkSize = 0; UInt32 chunkTag = 0; mObject = &pObject; mLwoFile.open( pFilename.c_str() ); if( mLwoFile.fail() ) { mLwoFile.close(); throw FileNotFoundException( pFilename, Here ); } try { if( ReadChunk( dataSize ) != ID_FORM ) throw InvalidLWOFileException( ID_FORM, Here ); if( ReadID4() != ID_LWO2 ) throw InvalidLWOFileException( ID_LWO2, Here ); dataRead += sizeof(ID_LWO2); while( dataRead < dataSize ) { chunkTag = ReadChunk(chunkSize); dataRead += sizeof(UInt32); // Chunk tag. dataRead += sizeof(UInt32); // Chunk size. switch( chunkTag ) { case ID_TAGS: ReadTAGS( chunkSize ); break; case ID_CLIP: ReadCLIP( chunkSize ); break; case ID_ENVL: ReadENVL( chunkSize ); break; case ID_LAYR: ReadLAYR( chunkSize ); break; case ID_PNTS: ReadPNTS( chunkSize ); break; case ID_BBOX: ReadBBOX( chunkSize ); break; case ID_POLS: ReadPOLS( chunkSize ); break; case ID_PTAG: ReadPTAG( chunkSize ); break; case ID_VMAP: case ID_VMAD: ReadVMAP( chunkSize, chunkTag == ID_VMAD ); break; case ID_SURF: ReadSURF( chunkSize ); break; default: Skip( chunkSize ); break; } dataRead += chunkSize; // Chunk bytes. } } catch( Exception& /*e*/ ) { mLwoFile.close(); throw; } // Fill data structure mLwoFile.close(); LWLayer* layer; Vector<LWLayer*>::iterator itLayer; for( itLayer = mObject->mLayers.begin(); itLayer != mObject->mLayers.end(); ++itLayer ) { layer = (*itLayer); mObject->GetBoundingBox ( layer->mPointList, layer->mBoundingBox ); mObject->GetPolyNormals ( layer->mPointList, layer->mPolygonList ); mObject->GetPointPolygons ( layer->mPointList, layer->mPolygonList ); mObject->ResolvePolySurfaces( layer->mPolygonList ); mObject->GetVertNormals ( layer->mPointList, layer->mPolygonList ); mObject->GetPointVMaps ( layer->mPointList, layer->mVertexMaps ); mObject->GetPolyVMaps ( layer->mPolygonList, layer->mVertexMaps ); } mObject = NULL; }
void LWOReader::ReadVMAP( UInt32 pChunkSize, Bool pPerPoly ) { UInt32 dataRead = 0; UInt16 dimension; LWIndex vertexIndex; LWIndex polygonIndex; LWVertexMap* newVertexMap = GD_NEW(LWVertexMap, this, "VertexMap"); newVertexMap->mPerPoly = pPerPoly; dataRead += ReadID4( newVertexMap->mType ); dataRead += ReadU2( dimension ); dataRead += ReadS0( newVertexMap->mName ); while( dataRead < pChunkSize ) { dataRead += ReadVX( vertexIndex ); newVertexMap->mVertexIndex.push_back( vertexIndex ); if( pPerPoly ) { dataRead += ReadVX( polygonIndex ); newVertexMap->mPolygonIndex.push_back( polygonIndex ); } LWMapValue mapping; switch( newVertexMap->mType ) { case ID_PICK: mapping.mPick = vertexIndex; break; case ID_WGHT: dataRead += ReadF4( mapping.mWeight ); break; case ID_TXUV: dataRead += ReadF4( mapping.mUV.U ); dataRead += ReadF4( mapping.mUV.V ); break; case ID_RGB: dataRead += ReadF4( mapping.mRGB.R ); dataRead += ReadF4( mapping.mRGB.G ); dataRead += ReadF4( mapping.mRGB.B ); break; case ID_RGBA: dataRead += ReadF4( mapping.mRGBA.R ); dataRead += ReadF4( mapping.mRGBA.G ); dataRead += ReadF4( mapping.mRGBA.B ); dataRead += ReadF4( mapping.mRGBA.A ); break; case ID_MORF: case ID_SPOT: case ID_MNVW: default: dataRead += Skip( dimension * sizeof(Float) ); break; } newVertexMap->mValues.push_back( mapping ); } GetCurrentLayer()->mVertexMaps.push_back( newVertexMap ); }