From 99174e4e5fb4b7079da80b35a6dfd68f3fd56a1c Mon Sep 17 00:00:00 2001 From: lbavoil Date: Fri, 25 Mar 2016 13:01:54 +0100 Subject: GFSDK_HBAO+_distro_r3.0_cl20573789 --- samples/D3D12/src/WaveFrontReader.h | 541 ++++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 samples/D3D12/src/WaveFrontReader.h (limited to 'samples/D3D12/src/WaveFrontReader.h') diff --git a/samples/D3D12/src/WaveFrontReader.h b/samples/D3D12/src/WaveFrontReader.h new file mode 100644 index 0000000..f68f2bf --- /dev/null +++ b/samples/D3D12/src/WaveFrontReader.h @@ -0,0 +1,541 @@ +//-------------------------------------------------------------------------------------- +// File: WaveFrontReader.h +// +// Code for loading basic mesh data from a WaveFront OBJ file +// +// http://en.wikipedia.org/wiki/Wavefront_.obj_file +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkID=324981 +//-------------------------------------------------------------------------------------- + +#include + +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +#include +#include + +template +class WaveFrontReader +{ +public: + typedef index_t index_t; + + struct Vertex + { + DirectX::XMFLOAT3 position; + DirectX::XMFLOAT3 normal; + DirectX::XMFLOAT2 textureCoordinate; + }; + + WaveFrontReader() : hasNormals(false), hasTexcoords(false) {} + + HRESULT Load( _In_z_ const wchar_t* szFileName, bool ccw = true ) + { + Clear(); + + static const size_t MAX_POLY = 64; + + using namespace DirectX; + + std::wifstream InFile( szFileName ); + if( !InFile ) + return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ); + + WCHAR fname[_MAX_FNAME]; + _wsplitpath_s( szFileName, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, nullptr, 0 ); + + name = fname; + + std::vector positions; + std::vector normals; + std::vector texCoords; + + VertexCache vertexCache; + + Material defmat; + + wcscpy_s( defmat.strName, L"default" ); + materials.push_back( defmat ); + + uint32_t curSubset = 0; + + WCHAR strCommand[256] = {0}; + WCHAR strMaterialFilename[MAX_PATH] = {0}; + for( ;; ) + { + InFile >> strCommand; + if( !InFile ) + break; + + if( 0 == wcscmp( strCommand, L"#" ) ) + { + // Comment + } + else if( 0 == wcscmp( strCommand, L"v" ) ) + { + // Vertex Position + float x, y, z; + InFile >> x >> y >> z; + positions.push_back( XMFLOAT3( x, y, z ) ); + } + else if( 0 == wcscmp( strCommand, L"vt" ) ) + { + // Vertex TexCoord + float u, v; + InFile >> u >> v; + texCoords.push_back( XMFLOAT2( u, v ) ); + + hasTexcoords = true; + } + else if( 0 == wcscmp( strCommand, L"vn" ) ) + { + // Vertex Normal + float x, y, z; + InFile >> x >> y >> z; + normals.push_back( XMFLOAT3( x, y, z ) ); + + hasNormals = true; + } + else if( 0 == wcscmp( strCommand, L"f" ) ) + { + // Face + UINT iPosition, iTexCoord, iNormal; + Vertex vertex; + + DWORD faceIndex[ MAX_POLY ]; + size_t iFace = 0; + for(;;) + { + if ( iFace >= MAX_POLY ) + { + // Too many polygon verts for the reader + return E_FAIL; + } + + memset( &vertex, 0, sizeof( vertex ) ); + + // OBJ format uses 1-based arrays + InFile >> iPosition; + if ( iPosition > positions.size() ) + return E_FAIL; + + vertex.position = positions[ iPosition - 1 ]; + + if( '/' == InFile.peek() ) + { + InFile.ignore(); + + if( '/' != InFile.peek() ) + { + // Optional texture coordinate + InFile >> iTexCoord; + if ( iTexCoord > texCoords.size() ) + return E_FAIL; + + vertex.textureCoordinate = texCoords[ iTexCoord - 1 ]; + } + + if( '/' == InFile.peek() ) + { + InFile.ignore(); + + // Optional vertex normal + InFile >> iNormal; + if ( iNormal > normals.size() ) + return E_FAIL; + + vertex.normal = normals[ iNormal - 1 ]; + } + } + + // If a duplicate vertex doesn't exist, add this vertex to the Vertices + // list. Store the index in the Indices array. The Vertices and Indices + // lists will eventually become the Vertex Buffer and Index Buffer for + // the mesh. + DWORD index = AddVertex( iPosition, &vertex, vertexCache ); + if ( index == (DWORD)-1 ) + return E_OUTOFMEMORY; + +#pragma warning( suppress : 4127 ) + if ( sizeof(index_t) == 2 && ( index >= 0xFFFF ) ) + { + // Too many indices for 16-bit IB! + return E_FAIL; + } + else if ( sizeof(index_t) == 4 && ( index >= 0xFFFFFFFF ) ) + { + // Too many indices for 32-bit IB! + return E_FAIL; + } + + faceIndex[ iFace ] = index; + ++iFace; + + // Check for more face data or end of the face statement + bool faceEnd = false; + for(;;) + { + wchar_t p = InFile.peek(); + + if ( '\n' == p || !InFile ) + { + faceEnd = true; + break; + } + else if ( isdigit( p ) ) + break; + + InFile.ignore(); + } + + if ( faceEnd ) + break; + } + + if ( iFace < 3 ) + { + // Need at least 3 points to form a triangle + return E_FAIL; + } + + // Convert polygons to triangles + DWORD i0 = faceIndex[0]; + DWORD i1 = faceIndex[1]; + + for( size_t j = 2; j < iFace; ++ j ) + { + DWORD index = faceIndex[ j ]; + indices.push_back( static_cast( i0 ) ); + if ( ccw ) + { + indices.push_back( static_cast( i1 ) ); + indices.push_back( static_cast( index ) ); + } + else + { + indices.push_back( static_cast( index ) ); + indices.push_back( static_cast( i1 ) ); + } + + attributes.push_back( curSubset ); + + i1 = index; + } + + assert( attributes.size()*3 == indices.size() ); + } + else if( 0 == wcscmp( strCommand, L"mtllib" ) ) + { + // Material library + InFile >> strMaterialFilename; + } + else if( 0 == wcscmp( strCommand, L"usemtl" ) ) + { + // Material + WCHAR strName[MAX_PATH] = {0}; + InFile >> strName; + + bool bFound = false; + uint32_t count = 0; + for( auto it = materials.cbegin(); it != materials.cend(); ++it, ++count ) + { + if( 0 == wcscmp( it->strName, strName ) ) + { + bFound = true; + curSubset = count; + break; + } + } + + if( !bFound ) + { + Material mat; + curSubset = static_cast( materials.size() ); + wcscpy_s( mat.strName, MAX_PATH - 1, strName ); + materials.push_back( mat ); + } + } + else + { + // Unimplemented or unrecognized command + //OutputDebugStringW( strCommand ); + } + + InFile.ignore( 1000, '\n' ); + } + + // Cleanup + InFile.close(); + + BoundingBox::CreateFromPoints( bounds, positions.size(), &positions.front(), sizeof(XMFLOAT3) ); + + // If an associated material file was found, read that in as well. + if (0) //@jihoc if( *strMaterialFilename ) + { + WCHAR ext[_MAX_EXT]; + _wsplitpath_s( strMaterialFilename, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT ); + + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + _wsplitpath_s( szFileName, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0 ); + + WCHAR szPath[ MAX_PATH ]; + _wmakepath_s( szPath, MAX_PATH, drive, dir, fname, ext ); + + HRESULT hr = LoadMTL( szPath ); + if ( FAILED(hr) ) + return hr; + } + + return S_OK; + } + + HRESULT LoadMTL( _In_z_ const wchar_t* szFileName ) + { + // Assumes MTL is in CWD along with OBJ + std::wifstream InFile( szFileName ); + if( !InFile ) + return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ); + + auto curMaterial = materials.end(); + + WCHAR strCommand[256] = {0}; + for( ;; ) + { + InFile >> strCommand; + if( !InFile ) + break; + + if( 0 == wcscmp( strCommand, L"newmtl" ) ) + { + // Switching active materials + WCHAR strName[MAX_PATH] = {0}; + InFile >> strName; + + curMaterial = materials.end(); + for( auto it = materials.begin(); it != materials.end(); ++it ) + { + if( 0 == wcscmp( it->strName, strName ) ) + { + curMaterial = it; + break; + } + } + } + + // The rest of the commands rely on an active material + if( curMaterial == materials.end() ) + continue; + + if( 0 == wcscmp( strCommand, L"#" ) ) + { + // Comment + } + else if( 0 == wcscmp( strCommand, L"Ka" ) ) + { + // Ambient color + float r, g, b; + InFile >> r >> g >> b; + curMaterial->vAmbient = XMFLOAT3( r, g, b ); + } + else if( 0 == wcscmp( strCommand, L"Kd" ) ) + { + // Diffuse color + float r, g, b; + InFile >> r >> g >> b; + curMaterial->vDiffuse = XMFLOAT3( r, g, b ); + } + else if( 0 == wcscmp( strCommand, L"Ks" ) ) + { + // Specular color + float r, g, b; + InFile >> r >> g >> b; + curMaterial->vSpecular = XMFLOAT3( r, g, b ); + } + else if( 0 == wcscmp( strCommand, L"d" ) || + 0 == wcscmp( strCommand, L"Tr" ) ) + { + // Alpha + InFile >> curMaterial->fAlpha; + } + else if( 0 == wcscmp( strCommand, L"Ns" ) ) + { + // Shininess + int nShininess; + InFile >> nShininess; + curMaterial->nShininess = nShininess; + } + else if( 0 == wcscmp( strCommand, L"illum" ) ) + { + // Specular on/off + int illumination; + InFile >> illumination; + curMaterial->bSpecular = ( illumination == 2 ); + } + else if( 0 == wcscmp( strCommand, L"map_Kd" ) ) + { + // Texture + InFile >> curMaterial->strTexture; + } + else + { + // Unimplemented or unrecognized command + } + + InFile.ignore( 1000, L'\n' ); + } + + InFile.close(); + + return S_OK; + } + + void Clear() + { + vertices.clear(); + indices.clear(); + attributes.clear(); + materials.clear(); + name.clear(); + hasNormals = false; + hasTexcoords = false; + + bounds.Center.x = bounds.Center.y = bounds.Center.z = 0.f; + bounds.Extents.x = bounds.Extents.y = bounds.Extents.z = 0.f; + } + + HRESULT LoadVBO( _In_z_ const wchar_t* szFileName ) + { + Clear(); + + WCHAR fname[_MAX_FNAME]; + _wsplitpath_s( szFileName, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, nullptr, 0 ); + + name = fname; + + Material defmat; + wcscpy_s( defmat.strName, L"default" ); + materials.push_back( defmat ); + + std::ifstream vboFile(szFileName, std::ifstream::in | std::ifstream::binary); + if ( !vboFile.is_open() ) + return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ); + + hasNormals = hasTexcoords = true; + + uint32_t numVertices = 0; + uint32_t numIndices = 0; + + vboFile.read( reinterpret_cast( &numVertices ), sizeof(uint32_t ) ); + if ( !numVertices ) + return E_FAIL; + + vboFile.read( reinterpret_cast( &numIndices ), sizeof(uint32_t ) ); + if ( !numIndices ) + return E_FAIL; + + vertices.resize( numVertices ); + vboFile.read( reinterpret_cast( &vertices.front() ), sizeof(Vertex) * numVertices ); + +#pragma warning( suppress : 4127 ) + if ( sizeof( index_t ) == 2 ) + { + indices.resize( numIndices ); + vboFile.read( reinterpret_cast( &indices.front() ), sizeof(uint16_t) * numIndices ); + } + else + { + std::vector tmp; + tmp.resize( numIndices ); + vboFile.read( reinterpret_cast( &tmp.front() ), sizeof(uint16_t) * numIndices ); + + indices.reserve( numIndices ); + for( auto it = tmp.cbegin(); it != tmp.cend(); ++it ) + { + indices.push_back( *it ); + } + } + + BoundingBox::CreateFromPoints( bounds, vertices.size(), reinterpret_cast( &vertices.front() ), sizeof(Vertex) ); + + vboFile.close(); + + return S_OK; + } + + struct Material + { + DirectX::XMFLOAT3 vAmbient; + DirectX::XMFLOAT3 vDiffuse; + DirectX::XMFLOAT3 vSpecular; + uint32_t nShininess; + float fAlpha; + + bool bSpecular; + + WCHAR strName[MAX_PATH]; + WCHAR strTexture[MAX_PATH]; + + Material() : + vAmbient( 0.2f, 0.2f, 0.2f ), + vDiffuse( 0.8f, 0.8f, 0.8f ), + vSpecular( 1.0f, 1.0f, 1.0f ), + nShininess( 0 ), + fAlpha( 1.f ), + bSpecular( false ) + { memset(strName, 0, MAX_PATH); memset(strTexture, 0, MAX_PATH); } + }; + + std::vector vertices; + std::vector indices; + std::vector attributes; + std::vector materials; + + std::wstring name; + bool hasNormals; + bool hasTexcoords; + + DirectX::BoundingBox bounds; + +private: + typedef std::unordered_multimap VertexCache; + + DWORD AddVertex( UINT hash, Vertex* pVertex, VertexCache& cache ) + { + auto f = cache.equal_range( hash ); + + for( auto it = f.first; it != f.second; ++it ) + { + auto& tv = vertices[ it->second ]; + + if ( 0 == memcmp( pVertex, &tv, sizeof(Vertex) ) ) + { + return it->second; + } + } + + DWORD index = static_cast( vertices.size() ); + vertices.push_back( *pVertex ); + + VertexCache::value_type entry( hash, index ); + cache.insert( entry ); + return index; + } +}; -- cgit v1.2.3