//-------------------------------------------------------------------------------- GeometryPtr GeometryLoaderDX11::loadStanfordPlyFile( std::wstring filename, bool withAdjacency ) { // Get the file path to the models FileSystem fs; filename = fs.GetModelsFolder() + filename; // Load the contents of the file std::ifstream fin; // Open the file and read the MS3D header data fin.open( filename.c_str(), std::ios::in ); if(!fin.is_open()) { // signal error - bad filename? throw new std::exception( "Could not open file" ); } // Parse the input std::string txt; // Read in header std::getline(fin, txt); if( 0 != txt.compare( "ply" ) ) { // signal error - not a PLY format file throw new std::exception( "File does not contain the correct header - 'PLY' expected." ); } std::getline(fin, txt); if( 0 != txt.compare( "format ascii 1.0" ) ) { // signal error - not a format of PLY that this code supports throw new std::exception( "File is not correct format - ASCII 1.0 expected." ); } std::vector< PlyElementDesc > elements; // Read in the rest of the header while(fin.is_open() && !fin.eof()) { // Grab the next line of the header std::getline(fin, txt); // If we're at the end then stop processing if(0 == txt.compare("end_header")) { break; } // If this line is a comment, skip to the next line else if(0 == txt.compare(0, 7, "comment")) { continue; } // If this line is an element, process it else if(0 == txt.compare(0, 7, "element")) { elements.push_back(ParsePLYElementHeader( txt, fin )); } // Otherwise, wtf? else { throw new std::exception("File header contains unexpected line beginning"); } } // Read all the raw data for( std::vector< PlyElementDesc >::iterator it = elements.begin(); it != elements.end(); ++it) { (*it).data = ReadPLYElementData(fin, *it); } // Create a resource to contain the geometry GeometryPtr MeshPtr = GeometryPtr( new GeometryDX11() ); // Convert data to D3D11 format int elemIdx = -1; // Pull out all the vertex data if(-1 < (elemIdx = FindPlyElementIndex(elements, "vertex"))) { PlyElementDesc d = elements.at( elemIdx ); // Has positions? int xIdx = FindPlyElementPropertyIndex( d.dataFormat, "x" ); int yIdx = FindPlyElementPropertyIndex( d.dataFormat, "y" ); int zIdx = FindPlyElementPropertyIndex( d.dataFormat, "z" ); if ((-1 != xIdx) && (-1 != yIdx) && (-1 != zIdx)) { VertexElementDX11 *pPositions = new VertexElementDX11( 3, d.elementCount ); pPositions->m_SemanticName = VertexElementDX11::PositionSemantic; pPositions->m_uiSemanticIndex = 0; pPositions->m_Format = DXGI_FORMAT_R32G32B32_FLOAT; pPositions->m_uiInputSlot = 0; pPositions->m_uiAlignedByteOffset = 0; pPositions->m_InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; pPositions->m_uiInstanceDataStepRate = 0; Vector3f* pRawPos = pPositions->Get3f( 0 ); for(int v = 0; v < d.elementCount; ++v) { void** raw = d.data.at(v); float x = *reinterpret_cast<float*>(raw[xIdx]); float y = *reinterpret_cast<float*>(raw[yIdx]); float z = *reinterpret_cast<float*>(raw[zIdx]); pRawPos[v] = Vector3f( x, y, z ); } MeshPtr->AddElement( pPositions ); } // Has normals? int nxIdx = FindPlyElementPropertyIndex( d.dataFormat, "nx" ); int nyIdx = FindPlyElementPropertyIndex( d.dataFormat, "ny" ); int nzIdx = FindPlyElementPropertyIndex( d.dataFormat, "nz" ); if ((-1 != nxIdx) && (-1 != nyIdx) && (-1 != nzIdx)) { VertexElementDX11 *pNormals = new VertexElementDX11( 3, d.elementCount ); pNormals->m_SemanticName = VertexElementDX11::NormalSemantic; pNormals->m_uiSemanticIndex = 0; pNormals->m_Format = DXGI_FORMAT_R32G32B32_FLOAT; pNormals->m_uiInputSlot = 0; pNormals->m_uiAlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; pNormals->m_InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; pNormals->m_uiInstanceDataStepRate = 0; Vector3f* pRawNorms = pNormals->Get3f( 0 ); for(int v = 0; v < d.elementCount; ++v) { void** raw = d.data.at(v); float x = *reinterpret_cast<float*>(raw[nxIdx]); float y = *reinterpret_cast<float*>(raw[nyIdx]); float z = *reinterpret_cast<float*>(raw[nzIdx]); pRawNorms[v] = Vector3f( x, y, z ); } MeshPtr->AddElement( pNormals ); } } else { throw new std::exception("Expected a 'vertex' element, but not found"); } // Pull out all the face index data if(-1 < (elemIdx = FindPlyElementIndex(elements, "face"))) { PlyElementDesc d = elements.at( elemIdx ); // Firstly, assert that the format is correct if((1 != d.dataFormat.size()) && d.dataFormat.at(0).isList && (0 == d.dataFormat.at(0).type.compare("uint"))) { // Expect a single list of integers throw new std::exception("Expected 'face' to be a single list of integers per-face"); } // Secondly, assert that each list is of the same dimension int faceSize = -1; for(int f = 0; f < d.elementCount; ++f) { void** raw = d.data.at(f); PlyDataArray<int>* idxs = reinterpret_cast<PlyDataArray<int>*>(raw[0]); if( -1 == faceSize) faceSize = idxs->length; else if(faceSize != idxs->length) throw new std::exception("Expected each face to have the same number of indexes"); } if(withAdjacency) { MeshPtr->SetPrimitiveType( (D3D11_PRIMITIVE_TOPOLOGY)(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + ((2*faceSize) - 1)) ); // Grab all of the faces so we can search for adjacency int* pRaw = new int[d.elementCount * faceSize]; int pRawIdx = 0; for(int f = 0; f < d.elementCount; ++f) { void** raw = d.data.at(f); PlyDataArray<int>* idxs = reinterpret_cast<PlyDataArray<int>*>(raw[0]); for(unsigned int fi = 0; fi < idxs->length; ++fi) pRaw[pRawIdx++] = idxs->data[fi]; } // We can now go and add the actual indices for(int f = 0; f < (d.elementCount * faceSize); f+=3) { MeshPtr->AddIndex( pRaw[f + 0] ); MeshPtr->AddIndex( pRaw[f + 1] ); MeshPtr->AddIndex( pRaw[f + 2] ); // We now need to find an adjacency for each // edge where possible int a0 = FindAdjacentIndex( pRaw[f + 0], pRaw[f + 1], pRaw[f + 2], pRaw, d.elementCount * faceSize ); int a1 = FindAdjacentIndex( pRaw[f + 1], pRaw[f + 2], pRaw[f + 0], pRaw, d.elementCount * faceSize ); int a2 = FindAdjacentIndex( pRaw[f + 2], pRaw[f + 0], pRaw[f + 1], pRaw, d.elementCount * faceSize ); std::wstringstream out; out << "Actual indices <" << pRaw[f+0] << ", " << pRaw[f+1] << ", " << pRaw[f+2] << "> have adjacency <" << a0 << ", " << a1 << ", " << a2 << ">."; OutputDebugString( out.str().c_str() ); OutputDebugString( L"\n" ); MeshPtr->AddIndex( a0 ); MeshPtr->AddIndex( a1 ); MeshPtr->AddIndex( a2 ); } delete[] pRaw; } else { // Thirdly, can now set the appropriate topology MeshPtr->SetPrimitiveType( (D3D11_PRIMITIVE_TOPOLOGY)(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (faceSize - 1)) ); // Finally, extract this data for(int f = 0; f < d.elementCount; ++f) { void** raw = d.data.at(f); PlyDataArray<int>* idxs = reinterpret_cast<PlyDataArray<int>*>(raw[0]); for(unsigned int fi = 0; fi < idxs->length; ++fi) MeshPtr->AddIndex( idxs->data[fi] ); } } } else { throw new std::exception("Expected a 'face' element, but not found"); } // Push into renderable resource MeshPtr->LoadToBuffers( ); // Release all intermediary memory for( std::vector< PlyElementDesc >::iterator it = elements.begin(); it != elements.end(); ++it) { PlyElementDesc d = *it; for(int e = 0; e < d.elementCount; ++e) { void** raw = d.data.at(e); if(d.dataFormat.at(0).isList) { PlyDataArray<void*>* rawArray = reinterpret_cast<PlyDataArray<void*>*>(raw[0]); SAFE_DELETE_ARRAY( rawArray->data ); SAFE_DELETE(raw[0]); } else { SAFE_DELETE(raw[0]); } } } // Return to caller return MeshPtr; }