diff --git a/UVAtlasTool/Mesh.cpp b/UVAtlasTool/Mesh.cpp new file mode 100644 index 0000000..5823a98 --- /dev/null +++ b/UVAtlasTool/Mesh.cpp @@ -0,0 +1,2602 @@ +//-------------------------------------------------------------------------------------- +// File: Mesh.cpp +// +// Mesh processing helper class +// +// 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 "mesh.h" + +#include +#include +#include + +using namespace DirectX; + +namespace +{ + struct handle_closer { void operator()(HANDLE h) { if (h) CloseHandle(h); } }; + + typedef public std::unique_ptr ScopedHandle; + + inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? 0 : h; } + + template inline HRESULT write_file(HANDLE hFile, const T& value) + { + DWORD bytesWritten; + if (!WriteFile(hFile, &value, static_cast(sizeof(T)), &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != sizeof(T)) + return E_FAIL; + + return S_OK; + } + + inline HRESULT write_file_string(HANDLE hFile, const WCHAR* value) + { + UINT length = (value) ? static_cast( wcslen(value)+1 ) : 1; + + DWORD bytesWritten; + if (!WriteFile(hFile, &length, static_cast(sizeof(UINT)), &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != sizeof(UINT)) + return E_FAIL; + + if (length > 0) + { + DWORD bytes = static_cast(sizeof(WCHAR) * length); + + if (!WriteFile(hFile, value, bytes, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytes) + return E_FAIL; + } + else + { + WCHAR nul = 0; + if (!WriteFile(hFile, &nul, sizeof(WCHAR), &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != sizeof(WCHAR)) + return E_FAIL; + } + + return S_OK; + } + + inline UINT64 roundup4k(UINT64 value) + { + return ((value + 4095) / 4096) * 4096; + } + + static const uint8_t g_padding[4096] = { 0 }; +} + +// Move constructor +Mesh::Mesh(Mesh&& moveFrom) +{ + *this = std::move(moveFrom); +} + +// Move operator +Mesh& Mesh::operator= (Mesh&& moveFrom) +{ + if (this != &moveFrom) + { + mnFaces = moveFrom.mnFaces; + mnVerts = moveFrom.mnVerts; + mIndices.swap( moveFrom.mIndices ); + mAttributes.swap( moveFrom.mAttributes ); + mAdjacency.swap( moveFrom.mAdjacency ); + mPositions.swap( moveFrom.mPositions ); + mNormals.swap( moveFrom.mNormals ); + mTangents.swap( moveFrom.mTangents ); + mBiTangents.swap( moveFrom.mBiTangents ); + mTexCoords.swap( moveFrom.mTexCoords ); + mColors.swap( moveFrom.mColors ); + mBlendIndices.swap( moveFrom.mBlendIndices ); + mBlendWeights.swap( moveFrom.mBlendWeights ); + } + return *this; +} + + +//-------------------------------------------------------------------------------------- +void Mesh::Clear() +{ + mnFaces = mnVerts = 0; + + // Release face data + mIndices.reset(); + mAttributes.reset(); + mAdjacency.reset(); + + // Release vertex data + mPositions.reset(); + mNormals.reset(); + mTangents.reset(); + mBiTangents.reset(); + mTexCoords.reset(); + mColors.reset(); + mBlendIndices.reset(); + mBlendWeights.reset(); +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::SetIndexData( size_t nFaces, const uint16_t* indices, uint32_t* attributes ) +{ + if ( !nFaces || !indices ) + return E_INVALIDARG; + + if ( ( uint64_t(nFaces) * 3 ) >= UINT32_MAX ) + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + + // Release face data + mnFaces = 0; + mIndices.reset(); + mAttributes.reset(); + + std::unique_ptr ib(new (std::nothrow) uint32_t[nFaces * 3]); + if (!ib) + return E_OUTOFMEMORY; + + for( size_t j = 0; j < (nFaces*3); ++j ) + { + if ( indices[ j ] == uint16_t(-1) ) + { + ib.get()[ j ] = uint32_t(-1); + } + else + { + ib.get()[ j ] = indices[ j ]; + } + } + + std::unique_ptr attr; + if ( attributes ) + { + attr.reset( new (std::nothrow) uint32_t[ nFaces ] ); + if ( !attr ) + return E_OUTOFMEMORY; + + memcpy( attr.get(), attributes, sizeof(uint32_t) * nFaces); + } + + mIndices.swap(ib); + mAttributes.swap(attr); + mnFaces = nFaces; + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Mesh::SetIndexData( size_t nFaces, const uint32_t* indices, uint32_t* attributes ) +{ + if ( !nFaces || !indices ) + return E_INVALIDARG; + + if ( ( uint64_t(nFaces) * 3 ) >= UINT32_MAX ) + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + + mnFaces = 0; + mIndices.reset(); + mAttributes.reset(); + + std::unique_ptr ib( new (std::nothrow) uint32_t[ nFaces * 3] ); + if ( !ib ) + return E_OUTOFMEMORY; + + memcpy( ib.get(), indices, sizeof(uint32_t) * nFaces * 3 ); + + std::unique_ptr attr; + if ( attributes ) + { + attr.reset( new (std::nothrow) uint32_t[ nFaces ] ); + if ( !attr ) + return E_OUTOFMEMORY; + + memcpy( attr.get(), attributes, sizeof(uint32_t) * nFaces ); + } + + mIndices.swap(ib); + mAttributes.swap(attr); + mnFaces = nFaces; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::SetVertexData( _Inout_ DirectX::VBReader& reader, _In_ size_t nVerts ) +{ + if ( !nVerts ) + return E_INVALIDARG; + + // Release vertex data + mnVerts = 0; + mPositions.reset(); + mNormals.reset(); + mTangents.reset(); + mBiTangents.reset(); + mTexCoords.reset(); + mColors.reset(); + mBlendIndices.reset(); + mBlendWeights.reset(); + + // Load positions (required) + std::unique_ptr pos( new (std::nothrow) XMFLOAT3[ nVerts ] ); + if (!pos) + return E_OUTOFMEMORY; + + HRESULT hr = reader.Read(pos.get(), "SV_Position", 0, nVerts); + if (FAILED(hr)) + return hr; + + // Load normals + std::unique_ptr norms; + auto e = reader.GetElement("NORMAL", 0); + if (e) + { + norms.reset(new (std::nothrow) XMFLOAT3[nVerts]); + if (!norms) + return E_OUTOFMEMORY; + + hr = reader.Read(norms.get(), "NORMAL", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Load tangents + std::unique_ptr tans1; + e = reader.GetElement("TANGENT", 0); + if (e) + { + tans1.reset(new (std::nothrow) XMFLOAT4[nVerts]); + if (!tans1) + return E_OUTOFMEMORY; + + hr = reader.Read(tans1.get(), "TANGENT", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Load bi-tangents + std::unique_ptr tans2; + e = reader.GetElement("BINORMAL", 0); + if (e) + { + tans2.reset(new (std::nothrow) XMFLOAT3[nVerts]); + if (!tans2) + return E_OUTOFMEMORY; + + hr = reader.Read(tans2.get(), "BINORMAL", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Load texture coordinates + std::unique_ptr texcoord; + e = reader.GetElement("TEXCOORD", 0); + if (e) + { + texcoord.reset(new (std::nothrow) XMFLOAT2[nVerts]); + if (!texcoord) + return E_OUTOFMEMORY; + + hr = reader.Read(texcoord.get(), "TEXCOORD", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Load vertex colors + std::unique_ptr colors; + e = reader.GetElement("COLOR", 0); + if (e) + { + colors.reset(new (std::nothrow) XMFLOAT4[nVerts]); + if (!colors) + return E_OUTOFMEMORY; + + hr = reader.Read(colors.get(), "COLOR", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Load skinning bone indices + std::unique_ptr blendIndices; + e = reader.GetElement("BLENDINDICES", 0); + if (e) + { + blendIndices.reset(new (std::nothrow) XMFLOAT4[nVerts]); + if (!blendIndices) + return E_OUTOFMEMORY; + + hr = reader.Read(blendIndices.get(), "BLENDINDICES", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Load skinning bone weights + std::unique_ptr blendWeights; + e = reader.GetElement("BLENDWEIGHT", 0); + if (e) + { + blendWeights.reset(new (std::nothrow) XMFLOAT4[nVerts]); + if (!blendWeights) + return E_OUTOFMEMORY; + + hr = reader.Read(blendWeights.get(), "BLENDWEIGHT", 0, nVerts); + if (FAILED(hr)) + return hr; + } + + // Return values + mPositions.swap( pos ); + mNormals.swap( norms ); + mTangents.swap( tans1 ); + mBiTangents.swap( tans2 ); + mTexCoords.swap( texcoord ); + mColors.swap( colors ); + mBlendIndices.swap( blendIndices ); + mBlendWeights.swap( blendWeights ); + mnVerts = nVerts; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::Validate(DWORD flags, std::wstring* msgs) const +{ + if (!mnFaces || !mIndices || !mnVerts) + return E_UNEXPECTED; + + return DirectX::Validate(mIndices.get(), mnFaces, mnVerts, mAdjacency.get(), flags, msgs); +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::Clean( _In_ bool breakBowties ) +{ + if (!mnFaces || !mIndices || !mnVerts || !mPositions) + return E_UNEXPECTED; + + std::vector dups; + HRESULT hr = DirectX::Clean(mIndices.get(), mnFaces, mnVerts, mAdjacency.get(), mAttributes.get(), dups, breakBowties); + if (FAILED(hr)) + return hr; + + if (dups.empty()) + { + // No vertex duplication is needed for mesh clean + return S_OK; + } + + size_t nNewVerts = mnVerts + dups.size(); + + std::unique_ptr pos(new (std::nothrow) XMFLOAT3[nNewVerts]); + if (!pos) + return E_OUTOFMEMORY; + + memcpy(pos.get(), mPositions.get(), sizeof(XMFLOAT3) * mnVerts); + + std::unique_ptr norms; + if (mNormals) + { + norms.reset(new (std::nothrow) XMFLOAT3[nNewVerts]); + if (!norms) + return E_OUTOFMEMORY; + + memcpy(norms.get(), mNormals.get(), sizeof(XMFLOAT3) * mnVerts); + } + + std::unique_ptr tans1; + if (mTangents) + { + tans1.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!tans1) + return E_OUTOFMEMORY; + + memcpy(tans1.get(), mTangents.get(), sizeof(XMFLOAT4) * mnVerts); + } + + std::unique_ptr tans2; + if (mBiTangents) + { + tans2.reset(new (std::nothrow) XMFLOAT3[nNewVerts]); + if (!tans2) + return E_OUTOFMEMORY; + + memcpy(tans2.get(), mBiTangents.get(), sizeof(XMFLOAT3) * mnVerts); + } + + std::unique_ptr texcoord; + if (mTexCoords) + { + texcoord.reset(new (std::nothrow) XMFLOAT2[nNewVerts]); + if (!texcoord) + return E_OUTOFMEMORY; + + memcpy(texcoord.get(), mTexCoords.get(), sizeof(XMFLOAT2) * mnVerts); + } + + std::unique_ptr colors; + if (mColors) + { + colors.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!colors) + return E_OUTOFMEMORY; + + memcpy(colors.get(), mColors.get(), sizeof(XMFLOAT4) * mnVerts); + } + + std::unique_ptr blendIndices; + if (mBlendIndices) + { + blendIndices.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!blendIndices) + return E_OUTOFMEMORY; + + memcpy(blendIndices.get(), mBlendIndices.get(), sizeof(XMFLOAT4) * mnVerts); + } + + std::unique_ptr blendWeights; + if (mBlendWeights) + { + blendWeights.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!blendWeights) + return E_OUTOFMEMORY; + + memcpy(blendWeights.get(), mBlendWeights.get(), sizeof(XMFLOAT4) * mnVerts); + } + + size_t j = mnVerts; + for (auto it = dups.begin(); it != dups.end() && (j < nNewVerts); ++it, ++j) + { + assert(*it < mnVerts); + + pos.get()[ j ] = mPositions.get()[ *it ]; + + if (norms) + { + norms.get()[ j ] = mNormals.get()[ *it ]; + } + + if (tans1) + { + tans1.get()[ j ] = mTangents.get()[ *it ]; + } + + if (tans2) + { + tans2.get()[ j ] = mBiTangents.get()[*it]; + } + + if (texcoord) + { + texcoord.get() [ j] = mTexCoords.get()[*it]; + } + + if (colors) + { + colors.get()[j] = mColors.get()[*it]; + } + + if (blendIndices) + { + blendIndices.get()[j] = mBlendIndices.get()[*it]; + } + + if (blendWeights) + { + blendWeights.get()[j] = mBlendWeights.get()[*it]; + } + } + + mPositions.swap(pos); + mNormals.swap(norms); + mTangents.swap(tans1); + mBiTangents.swap(tans2); + mTexCoords.swap(texcoord); + mColors.swap(colors); + mBlendIndices.swap(blendIndices); + mBlendWeights.swap(blendWeights); + mnVerts = nNewVerts; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::GenerateAdjacency( _In_ float epsilon ) +{ + if (!mnFaces || !mIndices || !mnVerts || !mPositions) + return E_UNEXPECTED; + + if ((uint64_t(mnFaces) * 3) >= UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + mAdjacency.reset( new (std::nothrow) uint32_t[ mnFaces * 3 ] ); + if ( !mAdjacency ) + return E_OUTOFMEMORY; + + return DirectX::GenerateAdjacencyAndPointReps(mIndices.get(), mnFaces, mPositions.get(), mnVerts, epsilon, nullptr, mAdjacency.get()); +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::ComputeNormals( _In_ DWORD flags ) +{ + if (!mnFaces || !mIndices || !mnVerts || !mPositions) + return E_UNEXPECTED; + + mNormals.reset( new (std::nothrow) XMFLOAT3[ mnVerts ] ); + if (!mNormals) + return E_OUTOFMEMORY; + + return DirectX::ComputeNormals(mIndices.get(), mnFaces, mPositions.get(), mnVerts, flags, mNormals.get()); +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::ComputeTangentFrame( _In_ bool bitangents ) +{ + if (!mnFaces || !mIndices || !mnVerts || !mPositions || !mNormals || !mTexCoords) + return E_UNEXPECTED; + + mTangents.reset(); + mBiTangents.reset(); + + std::unique_ptr tan1( new (std::nothrow) XMFLOAT4[mnVerts] ); + if (!tan1) + return E_OUTOFMEMORY; + + std::unique_ptr tan2; + if (bitangents) + { + tan2.reset( new (std::nothrow) XMFLOAT3[mnVerts] ); + if (!tan2) + return E_OUTOFMEMORY; + + HRESULT hr = DirectX::ComputeTangentFrame(mIndices.get(), mnFaces, mPositions.get(), mNormals.get(), mTexCoords.get(), mnVerts, + tan1.get(), tan2.get()); + if (FAILED(hr)) + return hr; + } + else + { + mBiTangents.reset(); + + HRESULT hr = DirectX::ComputeTangentFrame(mIndices.get(), mnFaces, mPositions.get(), mNormals.get(), mTexCoords.get(), mnVerts, + tan1.get()); + if (FAILED(hr)) + return hr; + } + + mTangents.swap( tan1 ); + mBiTangents.swap( tan2 ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::UpdateFaces( size_t nFaces, const uint32_t* indices ) +{ + if (!nFaces || !indices) + return E_INVALIDARG; + + if (!mnFaces || !mIndices) + return E_UNEXPECTED; + + if ( mnFaces != nFaces ) + return E_FAIL; + + if ((uint64_t(nFaces) * 3) >= UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + memcpy( mIndices.get(), indices, sizeof(uint32_t) * 3 * nFaces ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::UpdateAttributes( size_t nFaces, const uint32_t* attributes ) +{ + if (!nFaces || !attributes) + return E_INVALIDARG; + + if (!mnFaces || !mIndices || !mnVerts || !mPositions) + return E_UNEXPECTED; + + if ( mnFaces != nFaces ) + return E_FAIL; + + if ( !mAttributes ) + { + std::unique_ptr attr( new (std::nothrow) uint32_t[ nFaces ] ); + if ( !attr ) + return E_OUTOFMEMORY; + + memcpy( attr.get(), attributes, sizeof(uint32_t) * nFaces ); + + mAttributes.swap(attr); + } + else + { + memcpy( mAttributes.get(), attributes, sizeof(uint32_t) * nFaces ); + } + + std::unique_ptr remap(new (std::nothrow) uint32_t[mnFaces]); + if (!remap) + return E_OUTOFMEMORY; + + HRESULT hr = AttributeSort(mnFaces, mAttributes.get(), remap.get()); + if (FAILED(hr)) + return hr; + + if (mAdjacency) + { + hr = ReorderIBAndAdjacency(mIndices.get(), mnFaces, mAdjacency.get(), remap.get()); + } + else + { + hr = ReorderIB(mIndices.get(), mnFaces, remap.get()); + } + if (FAILED(hr)) + return hr; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::UpdateUVs(size_t nVerts, const XMFLOAT2* uvs) +{ + if (!nVerts || !uvs) + return E_INVALIDARG; + + if (!mnVerts || !mPositions) + return E_UNEXPECTED; + + if (nVerts != mnVerts) + return E_FAIL; + + if (!mTexCoords) + { + std::unique_ptr texcoord; + texcoord.reset(new (std::nothrow) XMFLOAT2[mnVerts]); + if (!texcoord) + return E_OUTOFMEMORY; + + memcpy(texcoord.get(), uvs, sizeof(XMFLOAT2) * mnVerts); + + mTexCoords.swap(texcoord); + } + else + { + memcpy(mTexCoords.get(), uvs, sizeof(XMFLOAT2) * mnVerts); + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::VertexRemap( const uint32_t* remap, size_t nNewVerts ) +{ + if (!remap || !nNewVerts) + return E_INVALIDARG; + + if (!mnVerts || !mPositions) + return E_UNEXPECTED; + + if (nNewVerts < mnVerts) + return E_FAIL; + + std::unique_ptr pos(new (std::nothrow) XMFLOAT3[nNewVerts]); + if (!pos) + return E_OUTOFMEMORY; + + HRESULT hr = UVAtlasApplyRemap(mPositions.get(), sizeof(XMFLOAT3), mnVerts, nNewVerts, remap, pos.get() ); + if (FAILED(hr)) + return hr; + + std::unique_ptr norms; + if (mNormals) + { + norms.reset(new (std::nothrow) XMFLOAT3[nNewVerts]); + if (!norms) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mNormals.get(), sizeof(XMFLOAT3), mnVerts, nNewVerts, remap, norms.get() ); + if (FAILED(hr)) + return hr; + } + + std::unique_ptr tans1; + if (mTangents) + { + tans1.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!tans1) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mTangents.get(), sizeof(XMFLOAT4), mnVerts, nNewVerts, remap, tans1.get() ); + if (FAILED(hr)) + return hr; + } + + std::unique_ptr tans2; + if (mBiTangents) + { + tans2.reset(new (std::nothrow) XMFLOAT3[nNewVerts]); + if (!tans2) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mBiTangents.get(), sizeof(XMFLOAT3), mnVerts, nNewVerts, remap, tans2.get() ); + if (FAILED(hr)) + return hr; + } + + std::unique_ptr texcoord; + if (mTexCoords) + { + texcoord.reset(new (std::nothrow) XMFLOAT2[nNewVerts]); + if (!texcoord) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mTexCoords.get(), sizeof(XMFLOAT2), mnVerts, nNewVerts, remap, texcoord.get() ); + if (FAILED(hr)) + return hr; + } + + std::unique_ptr colors; + if (mColors) + { + colors.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!colors) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mColors.get(), sizeof(XMFLOAT4), mnVerts, nNewVerts, remap, colors.get() ); + if (FAILED(hr)) + return hr; + } + + std::unique_ptr blendIndices; + if (mBlendIndices) + { + blendIndices.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!blendIndices) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mBlendIndices.get(), sizeof(XMFLOAT4), mnVerts, nNewVerts, remap, blendIndices.get() ); + if (FAILED(hr)) + return hr; + } + + std::unique_ptr blendWeights; + if (mBlendWeights) + { + blendWeights.reset(new (std::nothrow) XMFLOAT4[nNewVerts]); + if (!blendWeights) + return E_OUTOFMEMORY; + + hr = UVAtlasApplyRemap(mBlendWeights.get(), sizeof(XMFLOAT4), mnVerts, nNewVerts, remap, blendWeights.get() ); + if (FAILED(hr)) + return hr; + } + + mPositions.swap(pos); + mNormals.swap(norms); + mTangents.swap(tans1); + mBiTangents.swap(tans2); + mTexCoords.swap(texcoord); + mColors.swap(colors); + mBlendIndices.swap(blendIndices); + mBlendWeights.swap(blendWeights); + mnVerts = nNewVerts; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::ReverseWinding(bool texcoords) +{ + if (!mIndices || !mnFaces) + return E_UNEXPECTED; + + auto iptr = mIndices.get(); + for (size_t j = 0; j < mnFaces; ++j) + { + std::swap( *iptr, *(iptr + 2) ); + iptr += 3; + } + + if (texcoords && mTexCoords) + { + auto tptr = mTexCoords.get(); + for (size_t j = 0; j < mnVerts; ++j, ++tptr) + { + tptr->x = 1.f - tptr->x; + } + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::VisualizeUVs() +{ + if (!mnVerts || !mPositions || !mTexCoords) + return E_UNEXPECTED; + + const XMFLOAT2* sptr = mTexCoords.get(); + XMFLOAT3* dptr = mPositions.get(); + for (size_t j = 0; j < mnVerts; ++j) + { + dptr->x = sptr->x; + dptr->y = sptr->y; + dptr->z = 0; + ++sptr; + ++dptr; + } + + if (mNormals) + { + XMFLOAT3* nptr = mNormals.get(); + for (size_t j = 0; j < mnVerts; ++j) + { + XMStoreFloat3( nptr, g_XMIdentityR2 ); + ++nptr; + } + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +bool Mesh::Is16BitIndexBuffer() const +{ + if (!mIndices || !mnFaces) + return false; + + if ((uint64_t(mnFaces) * 3) >= UINT32_MAX) + return false; + + const uint32_t* iptr = mIndices.get(); + for (size_t j = 0; j < (mnFaces * 3); ++j ) + { + uint32_t index = *(iptr++); + if (index != uint32_t(-1) + && (index >= UINT16_MAX)) + { + return false; + } + } + + return true; +} + + +//-------------------------------------------------------------------------------------- +std::unique_ptr Mesh::GetIndexBuffer16() const +{ + std::unique_ptr ib; + + if (!mIndices || !mnFaces) + return ib; + + if ((uint64_t(mnFaces) * 3) >= UINT32_MAX) + return ib; + + size_t count = mnFaces * 3; + + ib.reset(new (std::nothrow) uint16_t[count]); + if (!ib) + return ib; + + const uint32_t* iptr = mIndices.get(); + for (size_t j = 0; j < count; ++j) + { + uint32_t index = *(iptr++); + if (index == uint32_t(-1)) + { + ib.get()[j] = uint16_t(-1); + } + else if (index >= UINT16_MAX) + { + ib.reset(); + return ib; + } + else + { + ib.get()[j] = static_cast(index); + } + } + + return ib; +} + + +//-------------------------------------------------------------------------------------- +HRESULT Mesh::GetVertexBuffer(_Inout_ DirectX::VBWriter& writer) const +{ + if (!mnVerts || !mPositions) + return E_UNEXPECTED; + + HRESULT hr = writer.Write(mPositions.get(), "SV_Position", 0, mnVerts ); + if (FAILED(hr)) + return hr; + + if (mNormals) + { + auto e = writer.GetElement("NORMAL", 0); + if (e) + { + hr = writer.Write(mNormals.get(), "NORMAL", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + if (mTangents) + { + auto e = writer.GetElement("TANGENT", 0); + if (e) + { + hr = writer.Write(mTangents.get(), "TANGENT", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + if (mBiTangents) + { + auto e = writer.GetElement("BINORMAL", 0); + if (e) + { + hr = writer.Write(mBiTangents.get(), "BINORMAL", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + if (mTexCoords) + { + auto e = writer.GetElement("TEXCOORD", 0); + if (e) + { + hr = writer.Write(mTexCoords.get(), "TEXCOORD", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + if (mColors) + { + auto e = writer.GetElement("COLOR", 0); + if (e) + { + hr = writer.Write(mColors.get(), "COLOR", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + if (mBlendIndices) + { + auto e = writer.GetElement("BLENDINDICES", 0); + if (e) + { + hr = writer.Write(mBlendIndices.get(), "BLENDINDICES", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + if (mBlendWeights) + { + auto e = writer.GetElement("BLENDWEIGHT", 0); + if (e) + { + hr = writer.Write(mBlendWeights.get(), "BLENDWEIGHT", 0, mnVerts); + if (FAILED(hr)) + return hr; + } + } + + return S_OK; +} + + +//====================================================================================== +// VBO +//====================================================================================== + +namespace VBO +{ + +#pragma pack(push,1) + + struct header_t + { + uint32_t numVertices; + uint32_t numIndices; + }; + + struct vertex_t + { + DirectX::XMFLOAT3 position; + DirectX::XMFLOAT3 normal; + DirectX::XMFLOAT2 textureCoordinate; + }; + +#pragma pack(pop) + + static_assert(sizeof(header_t) == 8, "VBO header size mismatch"); + static_assert(sizeof(vertex_t) == 32, "VBO vertex size mismatch"); +}; // namespace + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::ExportToVBO( const wchar_t* szFileName ) const +{ + using namespace VBO; + + if ( !szFileName ) + return E_INVALIDARG; + + if (!mnFaces || !mIndices || !mnVerts || !mPositions || !mNormals || !mTexCoords) + return E_UNEXPECTED; + + if ( ( uint64_t(mnFaces) * 3 ) >= UINT32_MAX ) + return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW ); + + if ( mnVerts >= UINT16_MAX ) + return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED ); + + // Setup VBO header + header_t header; + header.numVertices = static_cast( mnVerts ); + header.numIndices = static_cast( mnFaces*3 ); + + // Setup vertices/indices for VBO + + std::unique_ptr vb(new (std::nothrow) vertex_t[mnVerts]); + std::unique_ptr ib(new (std::nothrow) uint16_t[header.numIndices]); + if (!vb || !ib) + return E_OUTOFMEMORY; + + // Copy to VB + auto vptr = vb.get(); + for (size_t j = 0; j < mnVerts; ++j, ++vptr) + { + vptr->position = mPositions.get()[j]; + vptr->normal = mNormals.get()[j]; + vptr->textureCoordinate = mTexCoords.get()[j]; + } + + // Copy to IB + auto iptr = ib.get(); + for (size_t j = 0; j < header.numIndices; ++j, ++iptr) + { + uint32_t index = mIndices.get()[j]; + if (index == uint32_t(-1)) + { + *iptr = uint16_t(-1); + } + else if (index >= UINT16_MAX) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + else + { + *iptr = static_cast(index); + } + } + + // Write header and data +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + ScopedHandle hFile(safe_handle(CreateFile2(szFileName, GENERIC_WRITE, 0, CREATE_ALWAYS, 0))); +#else + ScopedHandle hFile(safe_handle(CreateFileW(szFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0))); +#endif + if (!hFile) + return HRESULT_FROM_WIN32(GetLastError()); + + HRESULT hr = write_file( hFile.get(), header ); + if (FAILED(hr)) + return hr; + + DWORD vertSize = static_cast( sizeof(vertex_t) * header.numVertices ); + + DWORD bytesWritten; + if (!WriteFile(hFile.get(), vb.get(), vertSize, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != vertSize) + return E_FAIL; + + DWORD indexSize = static_cast( sizeof(uint16_t) * header.numIndices ); + + if (!WriteFile(hFile.get(), ib.get(), indexSize, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != indexSize) + return E_FAIL; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::CreateFromVBO( const wchar_t* szFileName, std::unique_ptr& result ) +{ + using namespace VBO; + + if (!szFileName) + return E_INVALIDARG; + + result.reset(); + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + ScopedHandle hFile(safe_handle(CreateFile2(szFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr))); +#else + ScopedHandle hFile(safe_handle(CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr))); +#endif + if (!hFile) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + // Get the file size + LARGE_INTEGER FileSize = { 0 }; + +#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) + FILE_STANDARD_INFO fileInfo; + if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo))) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + FileSize = fileInfo.EndOfFile; +#else + GetFileSizeEx(hFile.get(), &FileSize); +#endif + + // File is too big for 32-bit allocation, so reject read + if (FileSize.HighPart > 0) + return E_FAIL; + + // Need at least enough data to read the header + if (FileSize.LowPart < sizeof(header_t)) + return E_FAIL; + + // Read VBO header + DWORD bytesRead = 0; + + header_t header; + if (!ReadFile(hFile.get(), &header, sizeof(header_t), &bytesRead, nullptr)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (bytesRead != sizeof(header)) + return E_FAIL; + + if (!header.numVertices || !header.numIndices) + return E_FAIL; + + result.reset( new (std::nothrow) Mesh ); + if (!result) + return E_OUTOFMEMORY; + + // Read vertices/indices from VBO + std::unique_ptr vb(new (std::nothrow) vertex_t[header.numVertices]); + std::unique_ptr ib( new (std::nothrow) uint16_t[ header.numIndices ] ); + if (!vb || !ib) + return E_OUTOFMEMORY; + + DWORD vertSize = static_cast( sizeof(vertex_t) * header.numVertices ); + + if (!ReadFile(hFile.get(), vb.get(), vertSize, &bytesRead, nullptr)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (bytesRead != vertSize) + return E_FAIL; + + DWORD indexSize = static_cast(sizeof(uint16_t) * header.numIndices ); + + if (!ReadFile(hFile.get(), ib.get(), indexSize, &bytesRead, nullptr)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + if (bytesRead != indexSize) + return E_FAIL; + + // Copy VB to result + std::unique_ptr pos(new (std::nothrow) XMFLOAT3[header.numVertices]); + std::unique_ptr norm(new (std::nothrow) XMFLOAT3[header.numVertices]); + std::unique_ptr texcoord(new (std::nothrow) XMFLOAT2[header.numVertices]); + if (!pos || !norm || !texcoord) + return E_OUTOFMEMORY; + + auto vptr = vb.get(); + for (size_t j = 0; j < header.numVertices; ++j, ++vptr) + { + pos.get()[ j ] = vptr->position; + norm.get()[ j ] = vptr->normal; + texcoord.get()[ j] = vptr->textureCoordinate; + } + + // Copy IB to result + std::unique_ptr indices(new (std::nothrow) uint32_t[header.numIndices]); + if (!indices) + return E_OUTOFMEMORY; + + auto iptr = ib.get(); + for (size_t j = 0; j < header.numIndices; ++j, ++iptr) + { + uint16_t index = *iptr; + if (index == uint16_t(-1)) + indices.get()[ j ] = uint32_t(-1); + else + indices.get()[ j ] = index; + } + + result->mPositions.swap(pos); + result->mNormals.swap(norm); + result->mTexCoords.swap(texcoord); + result->mIndices.swap(indices); + result->mnVerts = header.numVertices; + result->mnFaces = header.numIndices / 3; + + return S_OK; +} + + +//====================================================================================== +// Visual Studio CMO +//====================================================================================== + +//-------------------------------------------------------------------------------------- +// .CMO files are built by Visual Studio 2012 and an example renderer is provided +// in the VS Direct3D Starter Kit +// http://code.msdn.microsoft.com/Visual-Studio-3D-Starter-455a15f1 +//-------------------------------------------------------------------------------------- + +namespace VSD3DStarter +{ + // .CMO files + + // UINT - Mesh count + // { [Mesh count] + // UINT - Length of name + // wchar_t[] - Name of mesh (if length > 0) + // UINT - Material count + // { [Material count] + // UINT - Length of material name + // wchar_t[] - Name of material (if length > 0) + // Material structure + // UINT - Length of pixel shader name + // wchar_t[] - Name of pixel shader (if length > 0) + // { [8] + // UINT - Length of texture name + // wchar_t[] - Name of texture (if length > 0) + // } + // } + // BYTE - 1 if there is skeletal animation data present + // UINT - SubMesh count + // { [SubMesh count] + // SubMesh structure + // } + // UINT - IB Count + // { [IB Count] + // UINT - Number of USHORTs in IB + // USHORT[] - Array of indices + // } + // UINT - VB Count + // { [VB Count] + // UINT - Number of verts in VB + // Vertex[] - Array of vertices + // } + // UINT - Skinning VB Count + // { [Skinning VB Count] + // UINT - Number of verts in Skinning VB + // SkinningVertex[] - Array of skinning verts + // } + // MeshExtents structure + // [If skeleton animation data is not present, file ends here] + // UINT - Bone count + // { [Bone count] + // UINT - Length of bone name + // wchar_t[] - Bone name (if length > 0) + // Bone structure + // } + // UINT - Animation clip count + // { [Animation clip count] + // UINT - Length of clip name + // wchar_t[] - Clip name (if length > 0) + // float - Start time + // float - End time + // UINT - Keyframe count + // { [Keyframe count] + // Keyframe structure + // } + // } + // } + +#pragma pack(push,1) + + struct Material + { + DirectX::XMFLOAT4 Ambient; + DirectX::XMFLOAT4 Diffuse; + DirectX::XMFLOAT4 Specular; + float SpecularPower; + DirectX::XMFLOAT4 Emissive; + DirectX::XMFLOAT4X4 UVTransform; + }; + + const uint32_t MAX_TEXTURE = 8; + + struct SubMesh + { + UINT MaterialIndex; + UINT IndexBufferIndex; + UINT VertexBufferIndex; + UINT StartIndex; + UINT PrimCount; + }; + + const uint32_t NUM_BONE_INFLUENCES = 4; + + struct Vertex + { + DirectX::XMFLOAT3 Position; + DirectX::XMFLOAT3 Normal; + DirectX::XMFLOAT4 Tangent; + UINT color; + DirectX::XMFLOAT2 TextureCoordinates; + }; + + struct SkinningVertex + { + UINT boneIndex[NUM_BONE_INFLUENCES]; + float boneWeight[NUM_BONE_INFLUENCES]; + }; + + struct MeshExtents + { + float CenterX, CenterY, CenterZ; + float Radius; + + float MinX, MinY, MinZ; + float MaxX, MaxY, MaxZ; + }; + + struct Bone + { + INT ParentIndex; + DirectX::XMFLOAT4X4 InvBindPos; + DirectX::XMFLOAT4X4 BindPos; + DirectX::XMFLOAT4X4 LocalTransform; + }; + + struct Clip + { + float StartTime; + float EndTime; + UINT keys; + }; + + struct Keyframe + { + UINT BoneIndex; + float Time; + DirectX::XMFLOAT4X4 Transform; + }; + +#pragma pack(pop) + +}; // namespace + +static_assert(sizeof(VSD3DStarter::Material) == 132, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::SubMesh) == 20, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::Vertex) == 52, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::SkinningVertex) == 32, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::MeshExtents) == 40, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::Bone) == 196, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::Clip) == 12, "CMO Mesh structure size incorrect"); +static_assert(sizeof(VSD3DStarter::Keyframe) == 72, "CMO Mesh structure size incorrect"); + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::ExportToCMO(const wchar_t* szFileName, size_t nMaterials, const Material* materials) const +{ + using namespace VSD3DStarter; + + if (!szFileName) + return E_INVALIDARG; + + if (nMaterials > 0 && !materials) + return E_INVALIDARG; + + if (!mnFaces || !mIndices || !mnVerts || !mPositions || !mNormals || !mTexCoords || !mTangents) + return E_UNEXPECTED; + + if ((uint64_t(mnFaces) * 3) >= UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + if (mnVerts >= UINT16_MAX) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + UINT nIndices = static_cast( mnFaces * 3 ); + + // Setup vertices/indices for CMO + std::unique_ptr vb(new (std::nothrow) Vertex[mnVerts]); + std::unique_ptr ib(new (std::nothrow) uint16_t[nIndices]); + if (!vb || !ib) + return E_OUTOFMEMORY; + + std::unique_ptr vbSkin; + if (mBlendIndices && mBlendWeights) + { + vbSkin.reset(new (std::nothrow) SkinningVertex[mnVerts]); + if (!vbSkin) + return E_OUTOFMEMORY; + } + + // Copy to VB + auto vptr = vb.get(); + for (size_t j = 0; j < mnVerts; ++j, ++vptr) + { + vptr->Position = mPositions.get()[j]; + vptr->Normal = mNormals.get()[j]; + vptr->Tangent = mTangents.get()[j]; + vptr->TextureCoordinates = mTexCoords.get()[j]; + + if (mColors) + { + XMVECTOR icolor = XMLoadFloat4(&mColors.get()[j]); + PackedVector::XMUBYTEN4 rgba; + PackedVector::XMStoreUByteN4(&rgba, icolor); + vptr->color = rgba.v; + } + else + vptr->color = 0xFFFFFFFF; + } + + // Copy to SkinVB + auto sptr = vbSkin.get(); + if ( sptr ) + { + for (size_t j = 0; j < mnVerts; ++j, ++sptr) + { + XMVECTOR v = XMLoadFloat4(&mBlendIndices.get()[j]); + XMStoreUInt4( reinterpret_cast( &sptr->boneIndex[0] ), v); + + const XMFLOAT4* w = &mBlendWeights.get()[j]; + sptr->boneWeight[0] = w->x; + sptr->boneWeight[1] = w->y; + sptr->boneWeight[2] = w->z; + sptr->boneWeight[3] = w->w; + } + } + + // Copy to IB + auto iptr = ib.get(); + for (size_t j = 0; j < nIndices; ++j, ++iptr) + { + uint32_t index = mIndices.get()[j]; + if (index == uint32_t(-1)) + { + *iptr = uint16_t(-1); + } + else if (index >= UINT16_MAX) + { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + else + { + *iptr = static_cast(index); + } + } + + // Create CMO file +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + ScopedHandle hFile(safe_handle(CreateFile2(szFileName, GENERIC_WRITE, 0, CREATE_ALWAYS, 0))); +#else + ScopedHandle hFile(safe_handle(CreateFileW(szFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0))); +#endif + if (!hFile) + return HRESULT_FROM_WIN32(GetLastError()); + + // Write 1 mesh, name based on the filename + UINT n = 1; + HRESULT hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + { + WCHAR fname[_MAX_FNAME]; + _wsplitpath_s(szFileName, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, nullptr, 0); + + hr = write_file_string(hFile.get(), fname); + if (FAILED(hr)) + return hr; + } + + // Write materials + static const Mesh::Material s_defMaterial = { L"default", false, 1.f, 1.f, + XMFLOAT3(0.2f, 0.2f, 0.2f), XMFLOAT3(0.8f, 0.8f, 0.8f), + XMFLOAT3(0.f, 0.f, 0.f), XMFLOAT3(0.f, 0.f, 0.f), L"" }; + + UINT materialCount = 1; + if (nMaterials > 0) + { + materialCount = static_cast(nMaterials); + } + else + { + nMaterials = 1; + materials = &s_defMaterial; + } + + hr = write_file(hFile.get(), materialCount); + if (FAILED(hr)) + return hr; + + for (UINT j = 0; j < materialCount; ++j) + { + auto& m = materials[j]; + + if ( !m.name.empty() ) + { + hr = write_file_string(hFile.get(), m.name.c_str() ); + } + else + { + WCHAR name[64]; + swprintf_s(name, L"material%03u\n", j); + hr = write_file_string(hFile.get(), name); + } + if (FAILED(hr)) + return hr; + + VSD3DStarter::Material mdata; + memset( &mdata, 0, sizeof(mdata) ); + + mdata.Ambient.x = m.ambientColor.x; + mdata.Ambient.y = m.ambientColor.y; + mdata.Ambient.z = m.ambientColor.z; + mdata.Ambient.w = 1.f; + + mdata.Diffuse.x = m.diffuseColor.x; + mdata.Diffuse.y = m.diffuseColor.y; + mdata.Diffuse.z = m.diffuseColor.z; + mdata.Diffuse.w = m.alpha; + + if (m.specularColor.x > 0.f || m.specularColor.y > 0.f || m.specularColor.z > 0.f) + { + mdata.Specular.x = m.specularColor.x; + mdata.Specular.y = m.specularColor.y; + mdata.Specular.z = m.specularColor.z; + mdata.SpecularPower = ( m.specularPower <= 0.f ) ? 16.f : m.specularPower; + } + else + { + mdata.SpecularPower = 1.f; + } + mdata.Specular.w = 1.f; + + mdata.Emissive.x = m.emissiveColor.x; + mdata.Emissive.y = m.emissiveColor.y; + mdata.Emissive.z = m.emissiveColor.z; + mdata.Emissive.w = 1.f; + + XMMATRIX id = XMMatrixIdentity(); + XMStoreFloat4x4(&mdata.UVTransform, id); + + hr = write_file(hFile.get(), mdata); + if (FAILED(hr)) + return hr; + + if (m.specularColor.x > 0.f || m.specularColor.y > 0.f || m.specularColor.z > 0.f) + { + hr = write_file_string(hFile.get(), L"phong.dgsl"); + } + else + { + hr = write_file_string(hFile.get(), L"lambert.dgsl"); + } + if (FAILED(hr)) + return hr; + + hr = write_file_string(hFile.get(), m.texture.c_str() ); + if (FAILED(hr)) + return hr; + + for (size_t k = 1; k < MAX_TEXTURE; ++k) + { + hr = write_file_string(hFile.get(), L"" ); + if (FAILED(hr)) + return hr; + } + } + + BYTE sd = 0; // No skeleton/animation data + hr = write_file(hFile.get(), sd); + if (FAILED(hr)) + return hr; + + if (mAttributes) + { + auto subsets = ComputeSubsets(mAttributes.get(), mnFaces); + + n = static_cast(subsets.size()); + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + size_t startIndex = 0; + for (auto it = subsets.cbegin(); it != subsets.end(); ++it) + { + SubMesh smesh; + smesh.MaterialIndex = mAttributes.get()[it->first]; + if (smesh.MaterialIndex >= nMaterials) + smesh.MaterialIndex = 0; + + smesh.IndexBufferIndex = 0; + smesh.VertexBufferIndex = 0; + smesh.StartIndex = static_cast( startIndex ); + smesh.PrimCount = static_cast( it->second ); + hr = write_file(hFile.get(), smesh); + if (FAILED(hr)) + return hr; + + if ((startIndex + (it->second * 3)) > mnFaces * 3) + return E_FAIL; + + startIndex += smesh.PrimCount * 3; + } + } + else + { + n = 1; + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + SubMesh smesh; + smesh.MaterialIndex = 0; + smesh.IndexBufferIndex = 0; + smesh.VertexBufferIndex = 0; + smesh.StartIndex = 0; + smesh.PrimCount = static_cast(mnFaces); + + hr = write_file(hFile.get(), smesh); + if (FAILED(hr)) + return hr; + } + + // Write indices (one IB shared across submeshes) + n = 1; + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + hr = write_file(hFile.get(), nIndices); + if (FAILED(hr)) + return hr; + + DWORD indexSize = static_cast(sizeof(uint16_t) * nIndices); + + DWORD bytesWritten; + if (!WriteFile(hFile.get(), ib.get(), indexSize, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != indexSize) + return E_FAIL; + + // Write vertices (one VB shared across submeshes) + n = 1; + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + n = static_cast( mnVerts ); + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + DWORD vertSize = static_cast(sizeof(Vertex) * mnVerts); + + if (!WriteFile(hFile.get(), vb.get(), vertSize, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != vertSize) + return E_FAIL; + + // Write skinning vertices (one SkinVB shared across submeshes) + if ( vbSkin ) + { + n = 1; + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + n = static_cast(mnVerts); + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + + DWORD skinVertSize = static_cast(sizeof(SkinningVertex) * mnVerts); + + if (!WriteFile(hFile.get(), vbSkin.get(), skinVertSize, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != skinVertSize) + return E_FAIL; + } + else + { + n = 0; + hr = write_file(hFile.get(), n); + if (FAILED(hr)) + return hr; + } + + // Write extents + { + BoundingSphere sphere; + BoundingSphere::CreateFromPoints(sphere, mnVerts, mPositions.get(), sizeof(XMFLOAT3)); + + BoundingBox box; + BoundingBox::CreateFromPoints(box, mnVerts, mPositions.get(), sizeof(XMFLOAT3)); + + MeshExtents extents; + extents.CenterX = sphere.Center.x; + extents.CenterY = sphere.Center.y; + extents.CenterZ = sphere.Center.z; + extents.Radius = sphere.Radius; + + extents.MinX = box.Center.x - box.Extents.x; + extents.MinY = box.Center.y - box.Extents.y; + extents.MinZ = box.Center.z - box.Extents.z; + + extents.MaxX = box.Center.x + box.Extents.x; + extents.MaxY = box.Center.y + box.Extents.y; + extents.MaxZ = box.Center.z + box.Extents.z; + + hr = write_file(hFile.get(), extents); + if (FAILED(hr)) + return hr; + } + + // No skeleton data, so no animations + + return S_OK; +} + + + +//====================================================================================== +// SDKMESH +//====================================================================================== + +//-------------------------------------------------------------------------------------- +// SDKMESH format is generated by the legacy DirectX SDK's Content Exporter and +// originally rendered by the DXUT helper class SDKMesh +// +// http://go.microsoft.com/fwlink/?LinkId=226208 +//-------------------------------------------------------------------------------------- +namespace DXUT +{ + // .SDKMESH files + + // SDKMESH_HEADER + // SDKMESH_VERTEX_BUFFER_HEADER header->VertexStreamHeadersOffset + // SDKMESH_INDEX_BUFFER_HEADER header->IndexStreamHeadersOffset + // SDKMESH_MESH header->MeshDataOffset + // SDKMESH_SUBSET header->SubsetDataOffset + // SDKMESH_FRAME header->FrameDataOffset + // SDKMESH_MATERIAL header->MaterialDataOffset + // [header->NonBufferDataSize] + // { [ header->NumVertexBuffers] + // VB data + // } + // { [ header->NumIndexBuffers] + // IB data + // } + + + // .SDDKANIM files + + // SDKANIMATION_FILE_HEADER + // BYTE[] - Length of fileheader->AnimationDataSize + + // .SDKMESH uses Direct3D 9 decls, but only a subset of these is ever generated by the legacy DirectX SDK Content Exporter + + // D3DDECLUSAGE_POSITION / D3DDECLTYPE_FLOAT3 + // (D3DDECLUSAGE_BLENDWEIGHT / D3DDECLTYPE_UBYTE4N + // D3DDECLUSAGE_BLENDINDICES / D3DDECLTYPE_UBYTE4)? + // (D3DDECLUSAGE_NORMAL / D3DDECLTYPE_FLOAT3 or D3DDECLTYPE_FLOAT16_4)? + // (D3DDECLUSAGE_COLOR / D3DDECLTYPE_D3DCOLOR)? + // (D3DDECLUSAGE_TEXCOORD / D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2 or D3DDECLTYPE_FLOAT16_2, D3DDECLTYPE_FLOAT3 or D3DDECLTYPE_FLOAT16_4, D3DDECLTYPE_FLOAT4 or D3DDECLTYPE_FLOAT16_4)* + // (D3DDECLUSAGE_TANGENT / D3DDECLTYPE_FLOAT3 or D3DDECLTYPE_FLOAT16_4)? + // (D3DDECLUSAGE_BINORMAL / D3DDECLTYPE_FLOAT3 or D3DDECLTYPE_FLOAT16_4)? + + enum D3DDECLUSAGE + { + D3DDECLUSAGE_POSITION = 0, + D3DDECLUSAGE_BLENDWEIGHT = 1, + D3DDECLUSAGE_BLENDINDICES = 2, + D3DDECLUSAGE_NORMAL = 3, + D3DDECLUSAGE_TEXCOORD = 5, + D3DDECLUSAGE_TANGENT = 6, + D3DDECLUSAGE_BINORMAL = 7, + D3DDECLUSAGE_COLOR = 10, + }; + + enum D3DDECLTYPE + { + D3DDECLTYPE_FLOAT1 = 0, // 1D float expanded to (value, 0., 0., 1.) + D3DDECLTYPE_FLOAT2 = 1, // 2D float expanded to (value, value, 0., 1.) + D3DDECLTYPE_FLOAT3 = 2, // 3D float expanded to (value, value, value, 1.) + D3DDECLTYPE_FLOAT4 = 3, // 4D float + D3DDECLTYPE_D3DCOLOR = 4, // 4D packed unsigned bytes mapped to 0. to 1. range + // Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A) + D3DDECLTYPE_UBYTE4 = 5, // 4D unsigned byte + D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0 + D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1) + D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1) + D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values + + D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused. + }; + +#pragma pack(push,4) + + struct D3DVERTEXELEMENT9 + { + WORD Stream; // Stream index + WORD Offset; // Offset in the stream in bytes + BYTE Type; // Data type + BYTE Method; // Processing method + BYTE Usage; // Semantics + BYTE UsageIndex; // Semantic index + }; + +#pragma pack(pop) + + //-------------------------------------------------------------------------------------- + // Hard Defines for the various structures + //-------------------------------------------------------------------------------------- + const uint32_t SDKMESH_FILE_VERSION = 101; + const uint32_t MAX_VERTEX_ELEMENTS = 32; + const uint32_t MAX_VERTEX_STREAMS = 16; + const uint32_t MAX_FRAME_NAME = 100; + const uint32_t MAX_MESH_NAME = 100; + const uint32_t MAX_SUBSET_NAME = 100; + const uint32_t MAX_MATERIAL_NAME = 100; + const uint32_t MAX_TEXTURE_NAME = MAX_PATH; + const uint32_t MAX_MATERIAL_PATH = MAX_PATH; + const uint32_t INVALID_FRAME = uint32_t(-1); + const uint32_t INVALID_MESH = uint32_t(-1); + const uint32_t INVALID_MATERIAL = uint32_t(-1); + const uint32_t INVALID_SUBSET = uint32_t(-1); + const uint32_t INVALID_ANIMATION_DATA = uint32_t(-1); + const uint32_t INVALID_SAMPLER_SLOT = uint32_t(-1); + const uint32_t ERROR_RESOURCE_VALUE = 1; + + template bool IsErrorResource(TYPE data) + { + if ((TYPE) ERROR_RESOURCE_VALUE == data) + return true; + return false; + } + + //-------------------------------------------------------------------------------------- + // Enumerated Types. These will have mirrors in both D3D9 and D3D11 + //-------------------------------------------------------------------------------------- + enum SDKMESH_PRIMITIVE_TYPE + { + PT_TRIANGLE_LIST = 0, + PT_TRIANGLE_STRIP, + PT_LINE_LIST, + PT_LINE_STRIP, + PT_POINT_LIST, + PT_TRIANGLE_LIST_ADJ, + PT_TRIANGLE_STRIP_ADJ, + PT_LINE_LIST_ADJ, + PT_LINE_STRIP_ADJ, + PT_QUAD_PATCH_LIST, + PT_TRIANGLE_PATCH_LIST, + }; + + enum SDKMESH_INDEX_TYPE + { + IT_16BIT = 0, + IT_32BIT, + }; + + enum FRAME_TRANSFORM_TYPE + { + FTT_RELATIVE = 0, + FTT_ABSOLUTE, //This is not currently used but is here to support absolute transformations in the future + }; + + //-------------------------------------------------------------------------------------- + // Structures. + //-------------------------------------------------------------------------------------- +#pragma pack(push,8) + + struct SDKMESH_HEADER + { + //Basic Info and sizes + UINT Version; + BYTE IsBigEndian; + UINT64 HeaderSize; + UINT64 NonBufferDataSize; + UINT64 BufferDataSize; + + //Stats + UINT NumVertexBuffers; + UINT NumIndexBuffers; + UINT NumMeshes; + UINT NumTotalSubsets; + UINT NumFrames; + UINT NumMaterials; + + //Offsets to Data + UINT64 VertexStreamHeadersOffset; + UINT64 IndexStreamHeadersOffset; + UINT64 MeshDataOffset; + UINT64 SubsetDataOffset; + UINT64 FrameDataOffset; + UINT64 MaterialDataOffset; + }; + + struct SDKMESH_VERTEX_BUFFER_HEADER + { + UINT64 NumVertices; + UINT64 SizeBytes; + UINT64 StrideBytes; + D3DVERTEXELEMENT9 Decl[MAX_VERTEX_ELEMENTS]; + union + { + UINT64 DataOffset; + ID3D11Buffer* pVB11; + }; + }; + + struct SDKMESH_INDEX_BUFFER_HEADER + { + UINT64 NumIndices; + UINT64 SizeBytes; + UINT IndexType; + union + { + UINT64 DataOffset; + ID3D11Buffer* pIB11; + }; + }; + + struct SDKMESH_MESH + { + char Name[MAX_MESH_NAME]; + BYTE NumVertexBuffers; + UINT VertexBuffers[MAX_VERTEX_STREAMS]; + UINT IndexBuffer; + UINT NumSubsets; + UINT NumFrameInfluences; //aka bones + + DirectX::XMFLOAT3 BoundingBoxCenter; + DirectX::XMFLOAT3 BoundingBoxExtents; + + union + { + UINT64 SubsetOffset; + INT* pSubsets; + }; + union + { + UINT64 FrameInfluenceOffset; + UINT* pFrameInfluences; + }; + }; + + struct SDKMESH_SUBSET + { + char Name[MAX_SUBSET_NAME]; + UINT MaterialID; + UINT PrimitiveType; + UINT64 IndexStart; + UINT64 IndexCount; + UINT64 VertexStart; + UINT64 VertexCount; + }; + + struct SDKMESH_FRAME + { + char Name[MAX_FRAME_NAME]; + UINT Mesh; + UINT ParentFrame; + UINT ChildFrame; + UINT SiblingFrame; + DirectX::XMFLOAT4X4 Matrix; + UINT AnimationDataIndex; //Used to index which set of keyframes transforms this frame + }; + + struct SDKMESH_MATERIAL + { + char Name[MAX_MATERIAL_NAME]; + + // Use MaterialInstancePath + char MaterialInstancePath[MAX_MATERIAL_PATH]; + + // Or fall back to d3d8-type materials + char DiffuseTexture[MAX_TEXTURE_NAME]; + char NormalTexture[MAX_TEXTURE_NAME]; + char SpecularTexture[MAX_TEXTURE_NAME]; + + DirectX::XMFLOAT4 Diffuse; + DirectX::XMFLOAT4 Ambient; + DirectX::XMFLOAT4 Specular; + DirectX::XMFLOAT4 Emissive; + FLOAT Power; + + union + { + UINT64 Force64_1; //Force the union to 64bits + ID3D11Texture2D* pDiffuseTexture11; + }; + union + { + UINT64 Force64_2; //Force the union to 64bits + ID3D11Texture2D* pNormalTexture11; + }; + union + { + UINT64 Force64_3; //Force the union to 64bits + ID3D11Texture2D* pSpecularTexture11; + }; + + union + { + UINT64 Force64_4; //Force the union to 64bits + ID3D11ShaderResourceView* pDiffuseRV11; + }; + union + { + UINT64 Force64_5; //Force the union to 64bits + ID3D11ShaderResourceView* pNormalRV11; + }; + union + { + UINT64 Force64_6; //Force the union to 64bits + ID3D11ShaderResourceView* pSpecularRV11; + }; + }; + + struct SDKANIMATION_FILE_HEADER + { + UINT Version; + BYTE IsBigEndian; + UINT FrameTransformType; + UINT NumFrames; + UINT NumAnimationKeys; + UINT AnimationFPS; + UINT64 AnimationDataSize; + UINT64 AnimationDataOffset; + }; + + struct SDKANIMATION_DATA + { + DirectX::XMFLOAT3 Translation; + DirectX::XMFLOAT4 Orientation; + DirectX::XMFLOAT3 Scaling; + }; + + struct SDKANIMATION_FRAME_DATA + { + char FrameName[MAX_FRAME_NAME]; + union + { + UINT64 DataOffset; + SDKANIMATION_DATA* pAnimationData; + }; + }; + +#pragma pack(pop) + +}; // namespace + +static_assert(sizeof(DXUT::D3DVERTEXELEMENT9) == 8, "Direct3D9 Decl structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_HEADER) == 104, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER) == 288, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER) == 32, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_MESH) == 224, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_SUBSET) == 144, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_FRAME) == 184, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKMESH_MATERIAL) == 1256, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKANIMATION_FILE_HEADER) == 40, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKANIMATION_DATA) == 40, "SDK Mesh structure size incorrect"); +static_assert(sizeof(DXUT::SDKANIMATION_FRAME_DATA) == 112, "SDK Mesh structure size incorrect"); + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT Mesh::ExportToSDKMESH(const wchar_t* szFileName, size_t nMaterials, const Material* materials) const +{ + using namespace DXUT; + + if (!szFileName) + return E_INVALIDARG; + + if (nMaterials > 0 && !materials) + return E_INVALIDARG; + + if (!mnFaces || !mIndices || !mnVerts || !mPositions) + return E_UNEXPECTED; + + if ((uint64_t(mnFaces) * 3) >= UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + // Build input layout/vertex decalaration + static const D3D11_INPUT_ELEMENT_DESC s_elements [] = + { + { "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 0 + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 1 + { "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 2 + { "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 3 + { "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 4 + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 5 + { "BLENDINDICES", 0, DXGI_FORMAT_R8G8B8A8_UINT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 6 + { "BLENDWEIGHT", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }, // 7 + }; + + static const D3DVERTEXELEMENT9 s_decls [] = + { + { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, // 0 + { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, // 1 + { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, // 2 + { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TANGENT, 0 }, // 3 + { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BINORMAL, 0 }, // 4 + { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, // 5 + { 0, 0, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, // 6 + { 0, 0, D3DDECLTYPE_UBYTE4N, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, // 7 + { 0xFF, 0, D3DDECLTYPE_UNUSED, 0, 0, 0 }, + }; + + static_assert((_countof(s_elements) + 1) == _countof(s_decls), "InputLayouts and Vertex Decls disagree"); + + SDKMESH_VERTEX_BUFFER_HEADER vbHeader = { 0 }; + vbHeader.NumVertices = mnVerts; + vbHeader.Decl[0] = s_decls[0]; + + D3D11_INPUT_ELEMENT_DESC inputLayout[MAX_VERTEX_ELEMENTS] = { 0 }; + inputLayout[0] = s_elements[0]; + + size_t nDecl = 1; + size_t stride = sizeof(XMFLOAT3); + + if (mBlendIndices && mBlendWeights) + { + // BLENDWEIGHT + vbHeader.Decl[nDecl] = s_decls[7]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[7]; + ++nDecl; + stride += sizeof(UINT); + + // BLENDINDICES + vbHeader.Decl[nDecl] = s_decls[6]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[6]; + ++nDecl; + stride += sizeof(UINT); + } + + if (mNormals) + { + vbHeader.Decl[nDecl] = s_decls[1]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[1]; + ++nDecl; + stride += sizeof(XMFLOAT3); + } + + if (mColors) + { + vbHeader.Decl[nDecl] = s_decls[2]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[2]; + ++nDecl; + stride += sizeof(UINT); + } + + if (mTexCoords) + { + vbHeader.Decl[nDecl] = s_decls[5]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[5]; + ++nDecl; + stride += sizeof(XMFLOAT2); + } + + if (mTangents) + { + vbHeader.Decl[nDecl] = s_decls[3]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[3]; + ++nDecl; + stride += sizeof(XMFLOAT3); + } + + if (mBiTangents) + { + vbHeader.Decl[nDecl] = s_decls[4]; + vbHeader.Decl[nDecl].Offset = static_cast(stride); + inputLayout[nDecl] = s_elements[4]; + ++nDecl; + stride += sizeof(XMFLOAT3); + } + + assert(nDecl < MAX_VERTEX_ELEMENTS); + vbHeader.Decl[nDecl] = s_decls[_countof(s_decls) - 1]; + + // Build vertex buffer + std::unique_ptr vb(new (std::nothrow) uint8_t[mnVerts * stride]); + if (!vb) + return E_OUTOFMEMORY; + + vbHeader.SizeBytes = mnVerts * stride; + vbHeader.StrideBytes = stride; + + { + VBWriter writer; + + HRESULT hr = writer.Initialize(inputLayout, nDecl); + if (FAILED(hr)) + return hr; + + hr = writer.AddStream(vb.get(), mnVerts, 0, stride); + if (FAILED(hr)) + return hr; + + hr = GetVertexBuffer(writer); + if (FAILED(hr)) + return hr; + } + + // Build index buffer + SDKMESH_INDEX_BUFFER_HEADER ibHeader = { 0 }; + ibHeader.NumIndices = mnFaces * 3; + + std::unique_ptr ib16; + if (Is16BitIndexBuffer()) + { + ibHeader.SizeBytes = mnFaces * 3 * sizeof(uint16_t); + ibHeader.IndexType = IT_16BIT; + + ib16 = GetIndexBuffer16(); + if (!ib16) + return E_OUTOFMEMORY; + } + else + { + ibHeader.SizeBytes = mnFaces * 3 * sizeof(uint32_t); + ibHeader.IndexType = IT_32BIT; + } + + // Build materials buffer + std::unique_ptr mats; + if (!nMaterials) + { + mats.reset(new (std::nothrow) SDKMESH_MATERIAL[1]); + if (!mats) + return E_OUTOFMEMORY; + + memset(mats.get(), 0, sizeof(SDKMESH_MATERIAL)); + + strcpy_s(mats[0].Name, "default"); + mats[0].Diffuse = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.f); + mats[0].Ambient = XMFLOAT4(0.2f, 02.f, 0.2f, 1.f); + mats[0].Power = 1.f; + } + else + { + mats.reset(new (std::nothrow) SDKMESH_MATERIAL[nMaterials]); + if (!mats) + return E_OUTOFMEMORY; + + for (size_t j = 0; j < nMaterials; ++j) + { + auto m0 = &materials[j]; + auto m = &mats[j]; + + memset( m, 0, sizeof(SDKMESH_MATERIAL) ); + + int result = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, + m0->name.c_str(), -1, + m->Name, MAX_MATERIAL_NAME, nullptr, FALSE); + if (!result) + { + *m->Name = 0; + } + + result = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, + m0->texture.c_str(), -1, + m->DiffuseTexture, MAX_TEXTURE_NAME, nullptr, FALSE); + if (!result) + { + *m->DiffuseTexture = 0; + } + + m->Diffuse.x = m0->diffuseColor.x; + m->Diffuse.y = m0->diffuseColor.y; + m->Diffuse.z = m0->diffuseColor.z; + m->Diffuse.w = m0->alpha; + + m->Ambient.x = m0->ambientColor.x; + m->Ambient.y = m0->ambientColor.y; + m->Ambient.z = m0->ambientColor.z; + m->Ambient.w = 1.f; + + if (m0->specularColor.x > 0.f || m0->specularColor.y > 0.f || m0->specularColor.z > 0.f) + { + m->Specular.x = m0->specularColor.x; + m->Specular.y = m0->specularColor.y; + m->Specular.z = m0->specularColor.z; + m->Power = ( m0->specularPower <= 0.f ) ? 16.f : m0->specularPower; + } + else + { + m->Power = 1.f; + } + + m->Emissive.x = m0->emissiveColor.x; + m->Emissive.y = m0->emissiveColor.y; + m->Emissive.z = m0->emissiveColor.z; + } + } + + // Build subsets + std::vector submeshes; + std::vector subsetArray; + if (mAttributes) + { + auto subsets = ComputeSubsets(mAttributes.get(), mnFaces); + + UINT64 startIndex = 0; + for (auto it = subsets.cbegin(); it != subsets.cend(); ++it) + { + subsetArray.push_back(static_cast(submeshes.size())); + + SDKMESH_SUBSET s = { 0 }; + s.MaterialID = mAttributes.get()[it->first]; + if (s.MaterialID >= nMaterials) + s.MaterialID = 0; + + s.PrimitiveType = PT_TRIANGLE_LIST; + s.IndexStart = startIndex; + s.IndexCount = it->second * 3; + s.VertexCount = mnVerts; + submeshes.push_back(s); + + if ((startIndex + s.IndexCount) > mnFaces * 3) + return E_FAIL; + + startIndex += s.IndexCount; + } + } + else + { + SDKMESH_SUBSET s = { 0 }; + s.PrimitiveType = PT_TRIANGLE_LIST; + s.IndexCount = mnFaces * 3; + s.VertexCount = mnVerts; + submeshes.push_back(s); + } + + // Create file +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + ScopedHandle hFile(safe_handle(CreateFile2(szFileName, GENERIC_WRITE, 0, CREATE_ALWAYS, 0))); +#else + ScopedHandle hFile(safe_handle(CreateFileW(szFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0))); +#endif + if (!hFile) + return HRESULT_FROM_WIN32(GetLastError()); + + // Write file header + SDKMESH_HEADER header = { 0 }; + header.Version = SDKMESH_FILE_VERSION; + header.IsBigEndian = 0; + + header.NumVertexBuffers = 1; + header.NumIndexBuffers = 1; + header.NumMeshes = 1; + header.NumTotalSubsets = static_cast( submeshes.size() ); + header.NumFrames = 1; + header.NumMaterials = (nMaterials > 0) ? static_cast(nMaterials) : 1; + + header.HeaderSize = sizeof(SDKMESH_HEADER) + sizeof(SDKMESH_VERTEX_BUFFER_HEADER) + sizeof(SDKMESH_INDEX_BUFFER_HEADER); + + size_t staticDataSize = sizeof(SDKMESH_MESH) + + header.NumTotalSubsets * sizeof(SDKMESH_SUBSET) + + sizeof(SDKMESH_FRAME) + + header.NumMaterials * sizeof(SDKMESH_MATERIAL); + + header.NonBufferDataSize = staticDataSize + subsetArray.size() * sizeof(UINT) + sizeof(UINT); + + header.BufferDataSize = roundup4k( vbHeader.SizeBytes ) + roundup4k( ibHeader.SizeBytes ); + + header.VertexStreamHeadersOffset = sizeof(SDKMESH_HEADER); + header.IndexStreamHeadersOffset = header.VertexStreamHeadersOffset + sizeof(SDKMESH_VERTEX_BUFFER_HEADER); + header.MeshDataOffset = header.IndexStreamHeadersOffset + sizeof(SDKMESH_INDEX_BUFFER_HEADER); + header.SubsetDataOffset = header.MeshDataOffset + sizeof(SDKMESH_MESH); + header.FrameDataOffset = header.SubsetDataOffset + header.NumTotalSubsets * sizeof(SDKMESH_SUBSET); + header.MaterialDataOffset = header.FrameDataOffset + sizeof(SDKMESH_FRAME); + + HRESULT hr = write_file(hFile.get(), header); + if (FAILED(hr)) + return hr; + + // Write buffer headers + UINT64 offset = header.HeaderSize + header.NonBufferDataSize; + + vbHeader.DataOffset = offset; + offset += roundup4k(vbHeader.SizeBytes); + + hr = write_file(hFile.get(), vbHeader); + if (FAILED(hr)) + return hr; + + ibHeader.DataOffset = offset; + offset += roundup4k(ibHeader.SizeBytes); + + hr = write_file(hFile.get(), ibHeader); + if (FAILED(hr)) + return hr; + + // Write mesh headers + assert(header.NumMeshes == 1); + offset = header.HeaderSize + staticDataSize; + + SDKMESH_MESH meshHeader = { 0 }; + meshHeader.NumVertexBuffers = 1; + meshHeader.NumFrameInfluences = 1; + + { + BoundingBox box; + BoundingBox::CreateFromPoints(box, mnVerts, mPositions.get(), sizeof(XMFLOAT3)); + + meshHeader.BoundingBoxCenter = box.Center; + meshHeader.BoundingBoxExtents = box.Extents; + } + + meshHeader.NumSubsets = static_cast(submeshes.size()); + meshHeader.SubsetOffset = offset; + offset += meshHeader.NumSubsets * sizeof(UINT); + meshHeader.FrameInfluenceOffset = offset; + offset += sizeof(UINT); + + hr = write_file(hFile.get(), meshHeader); + if (FAILED(hr)) + return hr; + + // Write subsets + DWORD bytesToWrite = static_cast( sizeof(SDKMESH_SUBSET) * submeshes.size() ); + DWORD bytesWritten; + if ( !WriteFile(hFile.get(), &submeshes.front(), bytesToWrite, &bytesWritten, nullptr) ) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + + // Write frames + SDKMESH_FRAME frame = { 0 }; + strcpy_s( frame.Name, "root"); + frame.ParentFrame = frame.ChildFrame = frame.SiblingFrame = DWORD(-1); + frame.AnimationDataIndex = INVALID_ANIMATION_DATA; + XMMATRIX id = XMMatrixIdentity(); + XMStoreFloat4x4(&frame.Matrix, id); + + hr = write_file(hFile.get(), frame); + if (FAILED(hr)) + return hr; + + // Write materials + bytesToWrite = static_cast(sizeof(SDKMESH_MATERIAL) * ((nMaterials > 0) ? nMaterials : 1)); + if (!WriteFile(hFile.get(), mats.get(), bytesToWrite, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + + // Write subset index list + assert(meshHeader.NumSubsets == subsetArray.size()); + bytesToWrite = meshHeader.NumSubsets * sizeof(UINT); + if (!WriteFile(hFile.get(), &subsetArray.front(), bytesToWrite, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + + // Write frame influence list + assert(meshHeader.NumFrameInfluences == 1); + UINT frameIndex = 0; + hr = write_file(hFile.get(), frameIndex); + if (FAILED(hr)) + return hr; + + // Write VB data + bytesToWrite = static_cast(vbHeader.SizeBytes); + if (!WriteFile(hFile.get(), vb.get(), bytesToWrite, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + + bytesToWrite = static_cast( roundup4k(vbHeader.SizeBytes) - vbHeader.SizeBytes ); + if (bytesToWrite > 0) + { + assert(bytesToWrite < sizeof(g_padding)); + if (!WriteFile(hFile.get(), g_padding, bytesToWrite, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + } + + // Write IB data + bytesToWrite = static_cast(ibHeader.SizeBytes); + if (!WriteFile(hFile.get(), (ib16) ? static_cast( ib16.get() ) : static_cast( mIndices.get() ), + bytesToWrite, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + + bytesToWrite = static_cast(roundup4k(ibHeader.SizeBytes) - ibHeader.SizeBytes); + if (bytesToWrite > 0) + { + assert(bytesToWrite < sizeof(g_padding)); + if (!WriteFile(hFile.get(), g_padding, bytesToWrite, &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != bytesToWrite) + return E_FAIL; + } + + return S_OK; +} diff --git a/UVAtlasTool/Mesh.h b/UVAtlasTool/Mesh.h new file mode 100644 index 0000000..e89243b --- /dev/null +++ b/UVAtlasTool/Mesh.h @@ -0,0 +1,133 @@ +//-------------------------------------------------------------------------------------- +// File: Mesh.h +// +// Mesh processing helper class +// +// 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 + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +#if defined(_XBOX_ONE) && defined(_TITLE) +#include +#define DCOMMON_H_INCLUDED +#else +#include +#endif + +#include + +#include "directxmesh.h" + +class Mesh +{ +public: + Mesh() : mnFaces(0), mnVerts(0) {} + Mesh(Mesh&& moveFrom); + Mesh& operator= (Mesh&& moveFrom); + + // Methods + void Clear(); + + HRESULT SetIndexData( _In_ size_t nFaces, _In_reads_(nFaces*3) const uint16_t* indices, _In_reads_opt_(nFaces) uint32_t* attributes = nullptr ); + HRESULT SetIndexData( _In_ size_t nFaces, _In_reads_(nFaces*3) const uint32_t* indices, _In_reads_opt_(nFaces) uint32_t* attributes = nullptr ); + + HRESULT SetVertexData( _Inout_ DirectX::VBReader& reader, _In_ size_t nVerts ); + + HRESULT Validate( _In_ DWORD flags, _In_opt_ std::wstring* msgs ) const; + + HRESULT Clean( _In_ bool breakBowties=false ); + + HRESULT GenerateAdjacency( _In_ float epsilon ); + + HRESULT ComputeNormals( _In_ DWORD flags ); + + HRESULT ComputeTangentFrame( _In_ bool bitangents ); + + HRESULT UpdateFaces( _In_ size_t nFaces, _In_reads_(nFaces*3) const uint32_t* indices ); + + HRESULT UpdateAttributes( _In_ size_t nFaces, _In_reads_(nFaces*3) const uint32_t* attributes ); + + HRESULT UpdateUVs( _In_ size_t nVerts, _In_reads_(nVerts) const DirectX::XMFLOAT2* uvs ); + + HRESULT VertexRemap( _In_reads_(nNewVerts) const uint32_t* remap, _In_ size_t nNewVerts ); + + HRESULT ReverseWinding( bool texcoords ); + + HRESULT VisualizeUVs(); + + // Accessors + const uint32_t* GetAttributeBuffer() const { return mAttributes.get(); } + const uint32_t* GetAdjacencyBuffer() const { return mAdjacency.get(); } + const DirectX::XMFLOAT3* GetPositionBuffer() const { return mPositions.get(); } + const DirectX::XMFLOAT3* GetNormalBuffer() const { return mNormals.get(); } + const DirectX::XMFLOAT2* GetTexCoordBuffer() const { return mTexCoords.get(); } + const DirectX::XMFLOAT4* GetTangentBuffer() const { return mTangents.get(); } + const DirectX::XMFLOAT4* GetColorBuffer() const { return mColors.get(); } + + size_t GetFaceCount() const { return mnFaces; } + size_t GetVertexCount() const { return mnVerts; } + + bool Is16BitIndexBuffer() const; + + const uint32_t* GetIndexBuffer() const { return mIndices.get(); } + std::unique_ptr GetIndexBuffer16() const; + + HRESULT GetVertexBuffer(_Inout_ DirectX::VBWriter& writer ) const; + + // Save mesh to file + struct Material + { + std::wstring name; + bool perVertexColor; + float specularPower; + float alpha; + DirectX::XMFLOAT3 ambientColor; + DirectX::XMFLOAT3 diffuseColor; + DirectX::XMFLOAT3 specularColor; + DirectX::XMFLOAT3 emissiveColor; + std::wstring texture; + }; + + HRESULT ExportToVBO( _In_z_ const wchar_t* szFileName ) const; + HRESULT ExportToCMO( _In_z_ const wchar_t* szFileName, _In_ size_t nMaterials, _In_reads_opt_(nMaterials) const Material* materials ) const; + HRESULT ExportToSDKMESH( _In_z_ const wchar_t* szFileName, _In_ size_t nMaterials, _In_reads_opt_(nMaterials) const Material* materials ) const; + + // Create mesh from file + static HRESULT CreateFromVBO( _In_z_ const wchar_t* szFileName, _Inout_ std::unique_ptr& result ); + +private: + size_t mnFaces; + size_t mnVerts; + std::unique_ptr mIndices; + std::unique_ptr mAttributes; + std::unique_ptr mAdjacency; + std::unique_ptr mPositions; + std::unique_ptr mNormals; + std::unique_ptr mTangents; + std::unique_ptr mBiTangents; + std::unique_ptr mTexCoords; + std::unique_ptr mColors; + std::unique_ptr mBlendIndices; + std::unique_ptr mBlendWeights; + + // Prevent copying + Mesh(Mesh const&); + Mesh& operator= (Mesh const&); +}; \ No newline at end of file diff --git a/UVAtlasTool/UVAtlas.cpp b/UVAtlasTool/UVAtlas.cpp new file mode 100644 index 0000000..567d7de --- /dev/null +++ b/UVAtlasTool/UVAtlas.cpp @@ -0,0 +1,1187 @@ +//-------------------------------------------------------------------------------------- +// File: UVAtlas.cpp +// +// UVAtlas command-line tool (sample for UVAtlas library) +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkID=512686 +//-------------------------------------------------------------------------------------- + +#define NOMINMAX + +#include +#include +#include + +#include +#include + +#include + +#include "uvatlas.h" +#include "directxtex.h" + +#include "Mesh.h" +#include "WaveFrontReader.h" + +using namespace DirectX; + +enum OPTIONS // Note: dwOptions below assumes 32 or less options. +{ + OPT_QUALITY = 1, + OPT_MAXCHARTS, + OPT_MAXSTRETCH, + OPT_GUTTER, + OPT_WIDTH, + OPT_HEIGHT, + OPT_TOPOLOGICAL_ADJ, + OPT_GEOMETRIC_ADJ, + OPT_NORMALS, + OPT_WEIGHT_BY_AREA, + OPT_WEIGHT_BY_EQUAL, + OPT_TANGENTS, + OPT_CTF, + OPT_COLOR_MESH, + OPT_UV_MESH, + OPT_IMT_TEXFILE, + OPT_IMT_VERTEX, + OPT_SDKMESH, + OPT_CMO, + OPT_VBO, + OPT_OUTPUTFILE, + OPT_CLOCKWISE, + OPT_OVERWRITE, + OPT_NODDS, + OPT_FLIP, + OPT_FLIPTC, + OPT_NOLOGO, + OPT_MAX +}; + +static_assert( OPT_MAX <= 32, "dwOptions is a DWORD bitfield" ); + +enum CHANNELS +{ + CHANNEL_NONE = 0, + CHANNEL_NORMAL, + CHANNEL_COLOR, + CHANNEL_TEXCOORD, +}; + +struct SConversion +{ + WCHAR szSrc [MAX_PATH]; +}; + +struct SValue +{ + LPCWSTR pName; + DWORD dwValue; +}; + +static const XMFLOAT3 g_ColorList[8] = +{ + XMFLOAT3( 1.0f, 0.5f, 0.5f ), + XMFLOAT3( 0.5f, 1.0f, 0.5f ), + XMFLOAT3( 1.0f, 1.0f, 0.5f ), + XMFLOAT3( 0.5f, 1.0f, 1.0f ), + XMFLOAT3( 1.0f, 0.5f, 0.75f ), + XMFLOAT3( 0.0f, 0.5f, 0.75f ), + XMFLOAT3( 0.5f, 0.5f, 0.75f ), + XMFLOAT3( 0.5f, 0.5f, 1.0f ), +}; + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +SValue g_pOptions[] = +{ + { L"q", OPT_QUALITY }, + { L"n", OPT_MAXCHARTS }, + { L"st", OPT_MAXSTRETCH }, + { L"g", OPT_GUTTER }, + { L"w", OPT_WIDTH }, + { L"h", OPT_HEIGHT }, + { L"ta", OPT_TOPOLOGICAL_ADJ }, + { L"ga", OPT_GEOMETRIC_ADJ }, + { L"nn", OPT_NORMALS }, + { L"na", OPT_WEIGHT_BY_AREA }, + { L"ne", OPT_WEIGHT_BY_EQUAL }, + { L"tt", OPT_TANGENTS }, + { L"tb", OPT_CTF }, + { L"c", OPT_COLOR_MESH }, + { L"t", OPT_UV_MESH }, + { L"it", OPT_IMT_TEXFILE }, + { L"iv", OPT_IMT_VERTEX }, + { L"o", OPT_OUTPUTFILE }, + { L"sdkmesh", OPT_SDKMESH }, + { L"cmo", OPT_CMO }, + { L"vbo", OPT_VBO }, + { L"cw", OPT_CLOCKWISE }, + { L"y", OPT_OVERWRITE }, + { L"nodds", OPT_NODDS }, + { L"flip", OPT_FLIP }, + { L"fliptc", OPT_FLIPTC }, + { L"nologo", OPT_NOLOGO }, + { nullptr, 0 } +}; + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#pragma prefast(disable : 26018, "Only used with static internal arrays") + +DWORD LookupByName(const WCHAR *pName, const SValue *pArray) +{ + while(pArray->pName) + { + if(!_wcsicmp(pName, pArray->pName)) + return pArray->dwValue; + + pArray++; + } + + return 0; +} + +const WCHAR* LookupByValue(DWORD pValue, const SValue *pArray) +{ + while(pArray->pName) + { + if(pValue == pArray->dwValue) + return pArray->pName; + + pArray++; + } + + return L""; +} + +void PrintLogo() +{ + wprintf( L"Microsoft (R) UVAtlas Command-line Tool\n"); + wprintf( L"Copyright (C) Microsoft Corp. All rights reserved.\n"); + wprintf( L"\n"); +} + + +void PrintUsage() +{ + PrintLogo(); + + wprintf( L"Usage: uvatlas \n"); + wprintf( L"\n"); + wprintf( L" -q sets quality level to DEFAULT, FAST or QUALITY\n"); + wprintf( L" -n maximum number of charts to generate (def: 0)\n"); + wprintf( L" -st maximum amount of stretch 0.0 to 1.0 (def: 0.16667)\n"); + wprintf( L" -g the gutter width betwen charts in texels (def: 2.0)\n"); + wprintf( L" -w texture width (def: 512)\n"); + wprintf( L" -h texture height (def: 512)\n"); + wprintf( L" -ta | -ga generate topological vs. geometric adjancecy (def: ta)\n"); + wprintf( L" -nn | -na | -ne generate normals weighted by angle/area/equal\n" ); + wprintf( L" -tt generate tangents\n"); + wprintf( L" -tb generate tangents & bi-tangents\n"); + wprintf( L" -cw faces are clockwise (defaults to counter-clockwise)\n"); + wprintf( L" -c generate mesh with colors showing charts\n"); + wprintf( L" -t generates a separate mesh with uvs - (*_texture)\n"); + wprintf( L" -it calculate IMT for the mesh using this texture map\n"); + wprintf( L" -iv calculate IMT using per-vertex data\n"); + wprintf( L" NORMAL, COLOR, TEXCOORD\n"); + wprintf( L" -sdkmesh|-cmo|-vbo output file type\n"); + wprintf( L" -nodds prevents extension renaming in exported materials\n"); + wprintf( L" -flip | -fliptc reverse winding of faces and/or flips texcoords\n"); + wprintf( L" -o output filename\n"); + wprintf( L" -y overwrite existing output file (if any)\n"); + wprintf( L" -nologo suppress copyright message\n"); + + wprintf( L"\n"); +} + + +//-------------------------------------------------------------------------------------- +HRESULT __cdecl UVAtlasCallback( float fPercentDone ) +{ + static ULONGLONG s_lastTick = 0; + + ULONGLONG tick = GetTickCount64(); + + if ( ( tick - s_lastTick ) > 1000 ) + { + wprintf( L"%.2f%% \r", fPercentDone * 100 ); + s_lastTick = tick; + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT LoadFromOBJ(const WCHAR* szFilename, std::unique_ptr& inMesh, std::vector& inMaterial, DWORD options ) +{ + WaveFrontReader wfReader; + HRESULT hr = wfReader.Load(szFilename, (options & (1 << OPT_CLOCKWISE)) ? false : true ); + if (FAILED(hr)) + return hr; + + inMesh.reset(new (std::nothrow) Mesh); + if (!inMesh) + return E_OUTOFMEMORY; + + if (wfReader.indices.empty() || wfReader.vertices.empty()) + return E_FAIL; + + hr = inMesh->SetIndexData(wfReader.indices.size() / 3, &wfReader.indices.front(), + wfReader.attributes.empty() ? nullptr : &wfReader.attributes.front()); + if (FAILED(hr)) + return hr; + + static const D3D11_INPUT_ELEMENT_DESC s_vboLayout [] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + static const D3D11_INPUT_ELEMENT_DESC s_vboLayoutAlt [] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + const D3D11_INPUT_ELEMENT_DESC* layout = s_vboLayout; + size_t nDecl = _countof(s_vboLayout); + + if (!wfReader.hasNormals && !wfReader.hasTexcoords) + { + nDecl = 1; + } + else if (wfReader.hasNormals && !wfReader.hasTexcoords) + { + nDecl = 2; + } + else if (!wfReader.hasNormals && wfReader.hasTexcoords) + { + layout = s_vboLayoutAlt; + nDecl = _countof(s_vboLayoutAlt); + } + + VBReader vbr; + hr = vbr.Initialize(layout, nDecl); + if (FAILED(hr)) + return hr; + + hr = vbr.AddStream(&wfReader.vertices.front(), wfReader.vertices.size(), 0, sizeof(WaveFrontReader::Vertex)); + if (FAILED(hr)) + return hr; + + hr = inMesh->SetVertexData(vbr, wfReader.vertices.size()); + if (FAILED(hr)) + return hr; + + if ( !wfReader.materials.empty() ) + { + inMaterial.clear(); + inMaterial.reserve(wfReader.materials.size()); + + for (auto it = wfReader.materials.cbegin(); it != wfReader.materials.cend(); ++it) + { + Mesh::Material mtl; + memset(&mtl, 0, sizeof(mtl)); + + mtl.name = it->strName; + mtl.specularPower = (it->bSpecular) ? float(it->nShininess) : 1.f; + mtl.alpha = it->fAlpha; + mtl.ambientColor = it->vAmbient; + mtl.diffuseColor = it->vDiffuse; + mtl.specularColor = (it->bSpecular) ? it->vSpecular : XMFLOAT3(0.f, 0.f, 0.f); + + WCHAR texture[_MAX_PATH] = { 0 }; + if (*it->strTexture) + { + WCHAR txext[_MAX_EXT]; + WCHAR txfname[_MAX_FNAME]; + _wsplitpath_s(it->strTexture, nullptr, 0, nullptr, 0, txfname, _MAX_FNAME, txext, _MAX_EXT); + + if (!(options & (1 << OPT_NODDS))) + { + wcscpy_s(txext, L".dds"); + } + + _wmakepath_s(texture, nullptr, nullptr, txfname, txext); + } + + mtl.texture = texture; + + inMaterial.push_back(mtl); + } + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +// Entry-point +//-------------------------------------------------------------------------------------- +#pragma prefast(disable : 28198, "Command-line tool, frees all memory on exit") + +int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) +{ + // Parameters and defaults + size_t maxCharts = 0; + float maxStretch = 0.16667f; + float gutter = 2.f; + size_t width = 512; + size_t height = 512; + CHANNELS perVertex = CHANNEL_NONE; + DWORD uvOptions = UVATLAS_DEFAULT; + + WCHAR szTexFile[MAX_PATH] = { 0 }; + WCHAR szOutputFile[MAX_PATH] = { 0 }; + + // Initialize COM (needed for WIC) + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if( FAILED(hr) ) + { + wprintf( L"Failed to initialize COM (%08X)\n", hr); + return 1; + } + + // Process command line + DWORD dwOptions = 0; + std::list conversion; + + for(int iArg = 1; iArg < argc; iArg++) + { + PWSTR pArg = argv[iArg]; + + if(('-' == pArg[0]) || ('/' == pArg[0])) + { + pArg++; + PWSTR pValue; + + for(pValue = pArg; *pValue && (':' != *pValue); pValue++); + + if(*pValue) + *pValue++ = 0; + + DWORD dwOption = LookupByName(pArg, g_pOptions); + + if(!dwOption || (dwOptions & (1 << dwOption))) + { + wprintf( L"ERROR: unknown command-line option '%s'\n\n", pArg); + PrintUsage(); + return 1; + } + + dwOptions |= (1 << dwOption); + + if ( OPT_NOLOGO != dwOption && OPT_OVERWRITE != dwOption + && OPT_CLOCKWISE != dwOption && OPT_NODDS != dwOption + && OPT_FLIP != dwOption && OPT_FLIPTC != dwOption + && OPT_NORMALS != dwOption && OPT_WEIGHT_BY_AREA != dwOption && OPT_WEIGHT_BY_EQUAL != dwOption + && OPT_TANGENTS != dwOption && OPT_CTF != dwOption + && OPT_TOPOLOGICAL_ADJ != dwOption && OPT_GEOMETRIC_ADJ != dwOption + && OPT_COLOR_MESH != dwOption && OPT_UV_MESH != dwOption + && OPT_SDKMESH != dwOption && OPT_CMO != dwOption && OPT_VBO != dwOption ) + { + if(!*pValue) + { + if((iArg + 1 >= argc)) + { + wprintf( L"ERROR: missing value for command-line option '%s'\n\n", pArg); + PrintUsage(); + return 1; + } + + iArg++; + pValue = argv[iArg]; + } + } + + switch(dwOption) + { + case OPT_QUALITY: + if ( !_wcsicmp( pValue, L"DEFAULT" ) ) + { + uvOptions = UVATLAS_DEFAULT; + } + else if ( !_wcsicmp( pValue, L"FAST" ) ) + { + uvOptions = UVATLAS_GEODESIC_FAST; + } + else if ( !_wcsicmp( pValue, L"QUALITY" ) ) + { + uvOptions = UVATLAS_GEODESIC_QUALITY; + } + else + { + wprintf( L"Invalid value specified with -q (%s)\n", pValue); + return 1; + } + break; + + case OPT_MAXCHARTS: + if (swscanf_s(pValue, L"%Iu", &maxCharts) != 1) + { + wprintf( L"Invalid value specified with -n (%s)\n", pValue); + return 1; + } + break; + + case OPT_MAXSTRETCH: + if (swscanf_s(pValue, L"%f", &maxStretch) != 1 + || maxStretch < 0.f + || maxStretch > 1.f ) + { + wprintf( L"Invalid value specified with -st (%s)\n", pValue); + return 1; + } + break; + + case OPT_GUTTER: + if (swscanf_s(pValue, L"%f", &gutter) != 1 + || gutter < 0.f ) + { + wprintf( L"Invalid value specified with -g (%s)\n", pValue); + return 1; + } + break; + + case OPT_WIDTH: + if (swscanf_s(pValue, L"%Iu", &width) != 1) + { + wprintf( L"Invalid value specified with -w (%s)\n", pValue); + return 1; + } + break; + + case OPT_HEIGHT: + if (swscanf_s(pValue, L"%Iu", &height) != 1) + { + wprintf( L"Invalid value specified with -h (%s)\n", pValue); + return 1; + } + break; + + case OPT_WEIGHT_BY_AREA: + if (dwOptions & (1 << OPT_WEIGHT_BY_EQUAL)) + { + wprintf(L"Can only use one of nn, na, or ne\n"); + return 1; + } + dwOptions |= (1 << OPT_NORMALS); + break; + + case OPT_WEIGHT_BY_EQUAL: + if (dwOptions & (1 << OPT_WEIGHT_BY_AREA)) + { + wprintf(L"Can only use one of nn, na, or ne\n"); + return 1; + } + dwOptions |= (1 << OPT_NORMALS); + break; + + case OPT_IMT_TEXFILE: + if ( dwOptions & (1 << OPT_IMT_VERTEX) ) + { + wprintf( L"Cannot use both if and iv at the same time\n" ); + return 1; + } + + wcscpy_s(szTexFile, MAX_PATH, pValue); + break; + + case OPT_IMT_VERTEX: + if ( dwOptions & (1 << OPT_IMT_TEXFILE) ) + { + wprintf( L"Cannot use both if and iv at the same time\n" ); + return 1; + } + + if ( !_wcsicmp( pValue, L"COLOR" ) ) + { + perVertex = CHANNEL_COLOR; + } + else if ( !_wcsicmp( pValue, L"NORMAL" ) ) + { + perVertex = CHANNEL_NORMAL; + } + else if ( !_wcsicmp( pValue, L"TEXCOORD" ) ) + { + perVertex = CHANNEL_TEXCOORD; + } + else + { + wprintf( L"Invalid value specified with -iv (%s)\n", pValue); + return 1; + } + break; + + case OPT_OUTPUTFILE: + wcscpy_s(szOutputFile, MAX_PATH, pValue); + break; + + case OPT_TOPOLOGICAL_ADJ: + if (dwOptions & (1 << OPT_GEOMETRIC_ADJ)) + { + wprintf(L"Cannot use both ta and ga at the same time\n"); + return 1; + } + break; + + case OPT_GEOMETRIC_ADJ: + if (dwOptions & (1 << OPT_TOPOLOGICAL_ADJ)) + { + wprintf(L"Cannot use both ta and ga at the same time\n"); + return 1; + } + break; + + case OPT_SDKMESH: + if ( dwOptions & ( (1 << OPT_VBO) | (1 << OPT_CMO) ) ) + { + wprintf( L"Can only use one of sdkmesh, cmo, or vbo\n" ); + return 1; + } + break; + + case OPT_CMO: + if ( dwOptions & ( (1 << OPT_VBO) | (1 << OPT_SDKMESH) ) ) + { + wprintf( L"Can only use one of sdkmesh, cmo, or vbo\n" ); + return 1; + } + break; + + case OPT_VBO: + if ( dwOptions & ( (1 << OPT_SDKMESH) | (1 << OPT_CMO) ) ) + { + wprintf( L"Can only use one of sdkmesh, cmo, or vbo\n" ); + return 1; + } + break; + + case OPT_FLIP: + if ( dwOptions & (1 << OPT_FLIPTC) ) + { + wprintf(L"Can only use flip or fliptc\n"); + return 1; + } + break; + + case OPT_FLIPTC: + if (dwOptions & (1 << OPT_FLIP)) + { + wprintf(L"Can only use flip or fliptc\n"); + return 1; + } + break; + } + } + else + { + SConversion conv; + wcscpy_s(conv.szSrc, MAX_PATH, pArg); + + conversion.push_back(conv); + } + } + + if(conversion.empty()) + { + PrintUsage(); + return 0; + } + + if ( *szOutputFile && conversion.size() > 1 ) + { + wprintf( L"Cannot use -o with multiple input files\n"); + return 1; + } + + if(~dwOptions & (1 << OPT_NOLOGO)) + PrintLogo(); + + // Process files + for( auto pConv = conversion.begin(); pConv != conversion.end(); ++pConv ) + { + WCHAR ext[_MAX_EXT]; + WCHAR fname[_MAX_FNAME]; + _wsplitpath_s( pConv->szSrc, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT ); + + if ( pConv != conversion.begin() ) + wprintf( L"\n"); + + wprintf( L"reading %s", pConv->szSrc ); + fflush(stdout); + + std::unique_ptr inMesh; + std::vector inMaterial; + hr = E_NOTIMPL; + if ( _wcsicmp( ext, L".vbo" ) == 0 ) + { + hr = Mesh::CreateFromVBO( pConv->szSrc, inMesh ); + } + else if ( _wcsicmp( ext, L".sdkmesh" ) == 0 ) + { + wprintf(L"\nERROR: Importing SDKMESH files not supported\n"); + return 1; + } + else if ( _wcsicmp( ext, L".cmo" ) == 0 ) + { + wprintf(L"\nERROR: Importing Visual Studio CMO files not supported\n"); + return 1; + } + else if ( _wcsicmp( ext, L".x" ) == 0 ) + { + wprintf( L"\nERROR: Legacy Microsoft X files not supported\n"); + return 1; + } + else + { + hr = LoadFromOBJ(pConv->szSrc, inMesh, inMaterial, dwOptions); + } + if (FAILED(hr)) + { + wprintf( L" FAILED (%08X)\n", hr); + return 1; + } + + size_t nVerts = inMesh->GetVertexCount(); + size_t nFaces = inMesh->GetFaceCount(); + + if (!nVerts || !nFaces) + { + wprintf( L"\nERROR: Invalid mesh\n" ); + return 1; + } + + assert(inMesh->GetPositionBuffer() != 0); + assert(inMesh->GetIndexBuffer() != 0); + + wprintf(L"\nVerts: %Iu, nFaces: %Iu", nVerts, nFaces); + + // Prepare mesh for processing + { + // Adjacency + float epsilon = (dwOptions & (1 << OPT_GEOMETRIC_ADJ)) ? 1e-5f : 0.f; + + hr = inMesh->GenerateAdjacency(epsilon); + if (FAILED(hr)) + { + wprintf( L"\nERROR: Failed generating adjacency (%08X)\n", hr ); + return 1; + } + + // Validation + std::wstring msgs; + hr = inMesh->Validate( VALIDATE_BACKFACING | VALIDATE_BOWTIES, &msgs ); + if (!msgs.empty()) + { + wprintf(L"\nWARNING: \n"); + wprintf(msgs.c_str()); + } + + // Clean + hr = inMesh->Clean( true ); + if (FAILED(hr)) + { + wprintf( L"\nERROR: Failed mesh clean (%08X)\n", hr ); + return 1; + } + else + { + size_t nNewVerts = inMesh->GetVertexCount(); + if (nVerts != nNewVerts) + { + wprintf(L" [%Iu vertex dups] ", nNewVerts - nVerts); + nVerts = nNewVerts; + } + } + } + + if (!inMesh->GetNormalBuffer()) + { + dwOptions |= 1 << OPT_NORMALS; + } + + if (!inMesh->GetTangentBuffer() && (dwOptions & (1 << OPT_CMO))) + { + dwOptions |= 1 << OPT_TANGENTS; + } + + // Compute vertex normals from faces + if ((dwOptions & (1 << OPT_NORMALS)) + || ((dwOptions & ((1 << OPT_TANGENTS) | (1 << OPT_CTF))) && !inMesh->GetNormalBuffer()) ) + { + DWORD flags = CNORM_DEFAULT; + + if (dwOptions & (1 << OPT_WEIGHT_BY_EQUAL)) + { + flags |= CNORM_WEIGHT_EQUAL; + } + else if (dwOptions & (1 << OPT_WEIGHT_BY_AREA)) + { + flags |= CNORM_WEIGHT_BY_AREA; + } + + if (dwOptions & (1 << OPT_CLOCKWISE)) + { + flags |= CNORM_WIND_CW; + } + + hr = inMesh->ComputeNormals( flags ); + if (FAILED(hr)) + { + wprintf( L"\nERROR: Failed computing normals (flags:%1X, %08X)\n", flags, hr ); + return 1; + } + } + + // Compute tangents and bitangents + if (dwOptions & ((1 << OPT_TANGENTS) | (1 << OPT_CTF))) + { + if (!inMesh->GetTexCoordBuffer()) + { + wprintf( L"\nERROR: Computing tangents/bi-tangents requires texture coordinates\n" ); + return 1; + } + + hr = inMesh->ComputeTangentFrame( (dwOptions & (1 << OPT_CTF)) ? true : false ); + if (FAILED(hr)) + { + wprintf(L"\nERROR: Failed computing tangent frame (%08X)\n", hr); + return 1; + } + } + + // Compute IMT + std::unique_ptr IMTData; + if ( dwOptions & ((1 << OPT_IMT_TEXFILE) | (1 << OPT_IMT_VERTEX)) ) + { + if (dwOptions & (1 << OPT_IMT_TEXFILE)) + { + if (!inMesh->GetTexCoordBuffer()) + { + wprintf( L"\nERROR: Computing IMT from texture requires texture coordinates\n" ); + return 1; + } + + WCHAR txext[_MAX_EXT]; + _wsplitpath_s(szTexFile, nullptr, 0, nullptr, 0, nullptr, 0, txext, _MAX_EXT); + + ScratchImage iimage; + + if (_wcsicmp(txext, L".dds") == 0) + { + hr = LoadFromDDSFile(szTexFile, DDS_FLAGS_NONE, nullptr, iimage); + } + else if (_wcsicmp(ext, L".tga") == 0) + { + hr = LoadFromTGAFile(szTexFile, nullptr, iimage); + } + else + { + hr = LoadFromWICFile(szTexFile, TEX_FILTER_DEFAULT, nullptr, iimage); + } + if (FAILED(hr)) + { + wprintf(L"\nWARNING: Failed to load texture for IMT (%08X):\n%s\n", hr, szTexFile ); + } + else + { + const Image* img = iimage.GetImage(0, 0, 0); + + ScratchImage floatImage; + if (img->format != DXGI_FORMAT_R32G32B32A32_FLOAT) + { + hr = Convert(*iimage.GetImage(0, 0, 0), DXGI_FORMAT_R32G32B32A32_FLOAT, TEX_FILTER_DEFAULT, 0.5f, floatImage); + if (FAILED(hr)) + { + img = nullptr; + wprintf(L"\nWARNING: Failed converting texture for IMT (%08X):\n%s\n", hr, szTexFile); + } + else + { + img = floatImage.GetImage(0, 0, 0); + } + } + + if ( img ) + { + wprintf(L"\nComputing IMT from file %s...\n", szTexFile); + IMTData.reset(new (std::nothrow) float[nFaces * 3]); + if (!IMTData) + { + wprintf(L"\nERROR: out of memory\n"); + return 1; + } + + hr = UVAtlasComputeIMTFromTexture(inMesh->GetPositionBuffer(), inMesh->GetTexCoordBuffer(), nVerts, + inMesh->GetIndexBuffer(), DXGI_FORMAT_R32_UINT, nFaces, + reinterpret_cast( img->pixels ), img->width, img->height, + UVATLAS_IMT_DEFAULT, UVAtlasCallback, IMTData.get()); + if (FAILED(hr)) + { + IMTData.reset(); + wprintf(L"WARNING: Failed to compute IMT from texture (%08X):\n%s\n", hr, szTexFile); + } + } + } + } + else + { + const WCHAR* szChannel = L"*unknown*"; + const float* pSignal = nullptr; + size_t signalDim = 0; + size_t signalStride = 0; + switch (perVertex) + { + case CHANNEL_NORMAL: + szChannel = L"normals"; + if (inMesh->GetNormalBuffer()) + { + pSignal = reinterpret_cast(inMesh->GetNormalBuffer()); + signalDim = 3; + signalStride = sizeof(XMFLOAT3); + } + break; + + case CHANNEL_COLOR: + szChannel = L"vertex colors"; + if (inMesh->GetColorBuffer()) + { + pSignal = reinterpret_cast(inMesh->GetColorBuffer()); + signalDim = 4; + signalStride = sizeof(XMFLOAT4); + } + break; + + case CHANNEL_TEXCOORD: + szChannel = L"texture coordinates"; + if (inMesh->GetTexCoordBuffer()) + { + pSignal = reinterpret_cast(inMesh->GetTexCoordBuffer()); + signalDim = 2; + signalStride = sizeof(XMFLOAT2); + } + break; + } + + if (!pSignal) + { + wprintf(L"\nWARNING: Mesh does not have channel %s for IMT\n", szChannel ); + } + else + { + wprintf(L"\nComputing IMT from %s...\n", szChannel); + + IMTData.reset(new (std::nothrow) float[nFaces * 3]); + if (!IMTData) + { + wprintf(L"\nERROR: out of memory\n"); + return 1; + } + + hr = UVAtlasComputeIMTFromPerVertexSignal( inMesh->GetPositionBuffer(), nVerts, + inMesh->GetIndexBuffer(), DXGI_FORMAT_R32_UINT, nFaces, + pSignal, signalDim, signalStride, UVAtlasCallback, IMTData.get() ); + + if (FAILED(hr)) + { + IMTData.reset(); + wprintf(L"WARNING: Failed to compute IMT from channel %s (%08X)\n", szChannel, hr ); + } + } + } + } + else + { + wprintf(L"\n"); + } + + // Perform UVAtlas isocharting + wprintf( L"Computing isochart atlas on mesh...\n" ); + + std::vector vb; + std::vector ib; + float outStretch = 0.f; + size_t outCharts = 0; + std::vector facePartitioning; + std::vector vertexRemapArray; + hr = UVAtlasCreate( inMesh->GetPositionBuffer(), nVerts, + inMesh->GetIndexBuffer(), DXGI_FORMAT_R32_UINT, nFaces, + maxCharts, maxStretch, width, height, gutter, + inMesh->GetAdjacencyBuffer(), nullptr, + IMTData.get(), + UVAtlasCallback, UVATLAS_DEFAULT_CALLBACK_FREQUENCY, + uvOptions, vb, ib, + &facePartitioning, + &vertexRemapArray, + &outStretch, &outCharts ); + if ( FAILED(hr) ) + { + if ( hr == HRESULT_FROM_WIN32( ERROR_INVALID_DATA ) ) + { + wprintf( L"\nERROR: Non-manifold mesh\n" ); + return 1; + } + else + { + wprintf( L"\nERROR: Failed creating isocharts (%08X)\n", hr ); + return 1; + } + } + + wprintf( L"Output # of charts: %Iu, resulting stretching %f, %Iu verts\n", outCharts, outStretch, vb.size()); + + assert((ib.size() / sizeof(uint32_t) ) == (nFaces*3)); + assert(facePartitioning.size() == nFaces); + assert(vertexRemapArray.size() == vb.size()); + + hr = inMesh->UpdateFaces( nFaces, reinterpret_cast( &ib.front() ) ); + if ( FAILED(hr) ) + { + wprintf(L"\nERROR: Failed applying atlas indices (%08X)\n", hr); + return 1; + } + + hr = inMesh->VertexRemap( &vertexRemapArray.front(), vertexRemapArray.size() ); + if ( FAILED(hr) ) + { + wprintf(L"\nERROR: Failed applying atlas vertex remap (%08X)\n", hr); + return 1; + } + + nVerts = vb.size(); + +#ifdef _DEBUG + std::wstring msgs; + hr = inMesh->Validate( VALIDATE_DEFAULT, &msgs ); + if (!msgs.empty()) + { + wprintf(L"\nWARNING: \n"); + wprintf(msgs.c_str()); + } +#endif + + // Copy isochart UVs into mesh + { + std::unique_ptr texcoord( new (std::nothrow) XMFLOAT2[nVerts] ); + if (!texcoord) + { + wprintf(L"\nERROR: out of memory\n"); + return 1; + } + + auto txptr = texcoord.get(); + size_t j = 0; + for (auto it = vb.cbegin(); it != vb.cend() && j < nVerts; ++it, ++txptr) + { + *txptr = it->uv; + } + + hr = inMesh->UpdateUVs( nVerts, texcoord.get() ); + if (FAILED(hr)) + { + wprintf(L"\nERROR: Failed to update with isochart UVs\n"); + return 1; + } + } + + if (dwOptions & (1 << OPT_COLOR_MESH)) + { + inMaterial.clear(); + inMaterial.reserve( _countof(g_ColorList) ); + + for( size_t j = 0; j < _countof(g_ColorList) && (j < outCharts); ++j ) + { + Mesh::Material mtl; + memset( &mtl, 0, sizeof(mtl) ); + + WCHAR matname[32]; + wsprintf( matname, L"Chart%02Iu", j+1 ); + mtl.name = matname; + mtl.specularPower = 1.f; + mtl.alpha = 1.f; + + XMVECTOR v = XMLoadFloat3( &g_ColorList[j] ); + XMStoreFloat3( &mtl.diffuseColor, v ); + + v = XMVectorScale( v, 0.2f ); + XMStoreFloat3( &mtl.ambientColor, v ); + + inMaterial.push_back(mtl); + } + + std::unique_ptr attr( new (std::nothrow) uint32_t[ nFaces ] ); + if ( !attr ) + { + wprintf(L"\nERROR: out of memory\n" ); + return 1; + } + + size_t j = 0; + for( auto it = facePartitioning.cbegin(); it != facePartitioning.cend(); ++it, ++j ) + { + attr.get()[j] = *it % _countof(g_ColorList); + } + + hr = inMesh->UpdateAttributes( nFaces, attr.get() ); + if ( FAILED(hr) ) + { + wprintf(L"\nERROR: Failed applying atlas attributes (%08X)\n", hr); + return 1; + } + } + + if (dwOptions & ((1 << OPT_FLIP) | (1 << OPT_FLIPTC))) + { + hr = inMesh->ReverseWinding( (dwOptions & (1 << OPT_FLIPTC)) ? true : false ); + if (FAILED(hr)) + { + wprintf(L"\nERROR: Failed reversing winding (%08X)\n", hr); + return 1; + } + } + + // Write results + wprintf(L"\n\t->\n"); + + WCHAR outputPath[ MAX_PATH ] = { 0 }; + WCHAR outputExt[ _MAX_EXT] = { 0 }; + + if ( *szOutputFile ) + { + wcscpy_s( outputPath, szOutputFile ); + + _wsplitpath_s( szOutputFile, nullptr, 0, nullptr, 0, nullptr, 0, outputExt, _MAX_EXT ); + } + else + { + if (dwOptions & (1 << OPT_VBO)) + { + wcscpy_s(outputExt, L".vbo"); + } + else if (dwOptions & (1 << OPT_CMO)) + { + wcscpy_s(outputExt, L".cmo"); + } + else + { + wcscpy_s(outputExt, L".sdkmesh"); + } + + WCHAR outFilename[ _MAX_FNAME ] = { 0 }; + wcscpy_s( outFilename, fname ); + + _wmakepath_s( outputPath, nullptr, nullptr, outFilename, outputExt ); + } + + if ( ~dwOptions & (1 << OPT_OVERWRITE) ) + { + if (GetFileAttributesW(outputPath) != INVALID_FILE_ATTRIBUTES) + { + wprintf(L"\nERROR: Output file already exists, use -y to overwrite:\n'%s'\n", outputPath); + return 1; + } + } + + if ( !_wcsicmp(outputExt, L".vbo") ) + { + if (!inMesh->GetNormalBuffer() || !inMesh->GetTexCoordBuffer()) + { + wprintf( L"\nERROR: VBO requires position, normal, and texcoord\n" ); + return 1; + } + + if (!inMesh->Is16BitIndexBuffer()) + { + wprintf(L"\nERROR: VBO only supports 16-bit indices\n"); + return 1; + } + + hr = inMesh->ExportToVBO(outputPath); + } + else if ( !_wcsicmp(outputExt, L".sdkmesh") ) + { + hr = inMesh->ExportToSDKMESH(outputPath, inMaterial.size(), &inMaterial.front()); + } + else if ( !_wcsicmp(outputExt, L".cmo") ) + { + if (!inMesh->GetNormalBuffer() || !inMesh->GetTexCoordBuffer() || !inMesh->GetTangentBuffer()) + { + wprintf(L"\nERROR: Visual Studio CMO requires position, normal, tangents, and texcoord\n"); + return 1; + } + + if (!inMesh->Is16BitIndexBuffer()) + { + wprintf(L"\nERROR: Visual Studio CMO only supports 16-bit indices\n"); + return 1; + } + + hr = inMesh->ExportToCMO(outputPath, inMaterial.size(), &inMaterial.front()); + } + else if ( !_wcsicmp(outputExt, L".x") ) + { + wprintf(L"\nERROR: Legacy Microsoft X files not supported\n"); + return 1; + } + else + { + wprintf(L"\nERROR: Unknown output file type '%s'\n", outputExt); + return 1; + } + + if (FAILED(hr)) + { + wprintf(L"\nERROR: Failed write (%08X):-> '%s'\n", hr, outputPath); + return 1; + } + + wprintf(L" %Iu vertices, %Iu faces written:\n'%s'\n", nVerts, nFaces, outputPath); + + // Write out UV mesh visualization + if (dwOptions & (1 << OPT_UV_MESH)) + { + hr = inMesh->VisualizeUVs(); + if (FAILED(hr)) + { + wprintf(L"\nERROR: Failed to create UV visualization mesh\n"); + return 1; + } + + WCHAR uvFilename[_MAX_FNAME] = { 0 }; + wcscpy_s(uvFilename, fname); + wcscat_s(uvFilename, L"_texture"); + + _wmakepath_s(outputPath, nullptr, nullptr, uvFilename, outputExt); + + if (!_wcsicmp(outputExt, L".vbo")) + { + hr = inMesh->ExportToVBO(outputPath); + } + else if (!_wcsicmp(outputExt, L".sdkmesh")) + { + hr = inMesh->ExportToSDKMESH(outputPath, inMaterial.size(), &inMaterial.front()); + } + else if (!_wcsicmp(outputExt, L".cmo")) + { + hr = inMesh->ExportToCMO(outputPath, inMaterial.size(), &inMaterial.front()); + } + if (FAILED(hr)) + { + wprintf(L"\nERROR: Failed uv mesh write (%08X):-> '%s'\n", hr, outputPath); + return 1; + } + wprintf(L"uv mesh visualization '%s'\n", outputPath); + } + } + + return 0; +} diff --git a/UVAtlasTool/UVAtlasTool_2010.sln b/UVAtlasTool/UVAtlasTool_2010.sln new file mode 100644 index 0000000..6bb7c74 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2010.sln @@ -0,0 +1,72 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UVAtlasTool", "UVAtlasTool_2010.vcxproj", "{A7969CB3-E89B-49B9-96E7-8A219785A7CB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXMesh", "..\..\DirectXMesh\DirectXMesh\DirectXMesh_Desktop_2010.vcxproj", "{6857F086-F6FE-4150-9ED7-7446F1C1C220}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXTex", "..\..\DirectXTex\DirectXTex\DirectXTex_Desktop_2010.vcxproj", "{371B9FA9-4C90-4AC6-A123-ACED756D6C77}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UVAtlas", "..\UVAtlas\UVAtlas_2010.vcxproj", "{D88B9472-4C81-4CDF-98E4-BEF9A877603C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Profile|Win32 = Profile|Win32 + Profile|x64 = Profile|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|Win32.Build.0 = Debug|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|x64.ActiveCfg = Debug|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|x64.Build.0 = Debug|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|Win32.ActiveCfg = Profile|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|Win32.Build.0 = Profile|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|x64.ActiveCfg = Profile|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|x64.Build.0 = Profile|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|Win32.ActiveCfg = Release|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|Win32.Build.0 = Release|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|x64.ActiveCfg = Release|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|x64.Build.0 = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.ActiveCfg = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.Build.0 = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.ActiveCfg = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.Build.0 = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.ActiveCfg = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.Build.0 = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.ActiveCfg = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.Build.0 = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.ActiveCfg = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.Build.0 = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.ActiveCfg = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.Build.0 = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.ActiveCfg = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.Build.0 = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.ActiveCfg = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.Build.0 = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.ActiveCfg = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.Build.0 = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.ActiveCfg = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.Build.0 = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.ActiveCfg = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.Build.0 = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.ActiveCfg = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.Build.0 = Release|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Debug|Win32.ActiveCfg = Debug|Win32 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Debug|Win32.Build.0 = Debug|Win32 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Debug|x64.ActiveCfg = Debug|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Debug|x64.Build.0 = Debug|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Profile|Win32.ActiveCfg = Release|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Profile|x64.ActiveCfg = Release|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Profile|x64.Build.0 = Release|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Release|Win32.ActiveCfg = Release|Win32 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Release|Win32.Build.0 = Release|Win32 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Release|x64.ActiveCfg = Release|x64 + {D88B9472-4C81-4CDF-98E4-BEF9A877603C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/UVAtlasTool/UVAtlasTool_2010.vcxproj b/UVAtlasTool/UVAtlasTool_2010.vcxproj new file mode 100644 index 0000000..7b9fad0 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2010.vcxproj @@ -0,0 +1,384 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Profile + Win32 + + + Profile + x64 + + + Release + Win32 + + + Release + x64 + + + + UVAtlasTool + {A7969CB3-E89B-49B9-96E7-8A219785A7CB} + UVAtlasTool + Win32Proj + + + + Application + Unicode + + + Application + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + false + true + + + false + true + + + false + true + + + false + true + + + + Level4 + Disabled + MultiThreadedDebugDLL + false + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;_DEBUG;DEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + EditAndContinue + EnableFastChecks + + + %(AdditionalOptions) + ole32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + Console + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + Disabled + MultiThreadedDebugDLL + false + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;_DEBUG;DEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + %(AdditionalOptions) + ole32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + Console + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + {6857f086-f6fe-4150-9ed7-7446f1c1c220} + + + {371b9fa9-4c90-4ac6-a123-aced756d6c77} + + + {d88b9472-4c81-4cdf-98e4-bef9a877603c} + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UVAtlasTool/UVAtlasTool_2010.vcxproj.filters b/UVAtlasTool/UVAtlasTool_2010.vcxproj.filters new file mode 100644 index 0000000..2890f03 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2010.vcxproj.filters @@ -0,0 +1,31 @@ + + + + + {8e114980-c1a3-4ada-ad7c-83caadf5daeb} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {2c3d4c8c-5d1a-459a-a05a-a4e4b608a44e} + fx;fxh;hlsl + + + + + + + + + + + + + + + + Resource Files + + + + + \ No newline at end of file diff --git a/UVAtlasTool/UVAtlasTool_2012.sln b/UVAtlasTool/UVAtlasTool_2012.sln new file mode 100644 index 0000000..ca000d9 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2012.sln @@ -0,0 +1,91 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UVAtlasTool", "UVAtlasTool_2012.vcxproj", "{A7969CB3-E89B-49B9-96E7-8A219785A7CB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXMesh", "..\..\DirectXMesh\DirectXMesh\DirectXMesh_Desktop_2012.vcxproj", "{6857F086-F6FE-4150-9ED7-7446F1C1C220}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXTex", "..\..\DirectXTex\DirectXTex\DirectXTex_Desktop_2012.vcxproj", "{371B9FA9-4C90-4AC6-A123-ACED756D6C77}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UVAtlas_2012", "..\UVAtlas\UVAtlas_2012.vcxproj", "{10359E70-6A7F-4433-8EF1-B0FB688D830E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Profile|Win32 = Profile|Win32 + Profile|x64 = Profile|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|Win32.Build.0 = Debug|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|x64.ActiveCfg = Debug|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|x64.Build.0 = Debug|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|Win32.ActiveCfg = Profile|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|Win32.Build.0 = Profile|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|x64.ActiveCfg = Profile|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|x64.Build.0 = Profile|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|Win32.ActiveCfg = Release|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|Win32.Build.0 = Release|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|x64.ActiveCfg = Release|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|x64.Build.0 = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.ActiveCfg = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.Build.0 = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.Deploy.0 = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.ActiveCfg = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.Build.0 = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.Deploy.0 = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.ActiveCfg = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.Build.0 = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.Deploy.0 = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.ActiveCfg = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.Build.0 = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.Deploy.0 = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.ActiveCfg = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.Build.0 = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.Deploy.0 = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.ActiveCfg = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.Build.0 = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.Deploy.0 = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.ActiveCfg = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.Build.0 = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.Deploy.0 = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.ActiveCfg = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.Build.0 = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.Deploy.0 = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.ActiveCfg = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.Build.0 = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.Deploy.0 = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.ActiveCfg = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.Build.0 = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.Deploy.0 = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.ActiveCfg = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.Build.0 = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.Deploy.0 = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.ActiveCfg = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.Build.0 = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.Deploy.0 = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|Win32.ActiveCfg = Debug|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|Win32.Build.0 = Debug|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|Win32.Deploy.0 = Debug|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|x64.ActiveCfg = Debug|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|x64.Build.0 = Debug|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|x64.Deploy.0 = Debug|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|Win32.ActiveCfg = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|Win32.Build.0 = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|Win32.Deploy.0 = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|x64.ActiveCfg = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|x64.Build.0 = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|x64.Deploy.0 = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|Win32.ActiveCfg = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|Win32.Build.0 = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|Win32.Deploy.0 = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|x64.ActiveCfg = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|x64.Build.0 = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/UVAtlasTool/UVAtlasTool_2012.vcxproj b/UVAtlasTool/UVAtlasTool_2012.vcxproj new file mode 100644 index 0000000..f253498 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2012.vcxproj @@ -0,0 +1,390 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Profile + Win32 + + + Profile + x64 + + + Release + Win32 + + + Release + x64 + + + + UVAtlasTool + {A7969CB3-E89B-49B9-96E7-8A219785A7CB} + UVAtlasTool + Win32Proj + $(VCTargetsPath11) + + + + Application + Unicode + v110 + + + Application + Unicode + v110 + + + Application + true + Unicode + v110 + + + Application + true + Unicode + v110 + + + Application + true + Unicode + v110 + + + Application + true + Unicode + v110 + + + + + + + + + + + + + + + + + + + + + + + + true + true + AllRules.ruleset + + + true + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + + Level4 + Disabled + MultiThreadedDebugDLL + false + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;_DEBUG;DEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + EditAndContinue + EnableFastChecks + + + %(AdditionalOptions) + ole32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + Console + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + Disabled + MultiThreadedDebugDLL + false + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;_DEBUG;DEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + %(AdditionalOptions) + ole32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + Console + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + {6857f086-f6fe-4150-9ed7-7446f1c1c220} + + + {371b9fa9-4c90-4ac6-a123-aced756d6c77} + + + {10359e70-6a7f-4433-8ef1-b0fb688d830e} + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UVAtlasTool/UVAtlasTool_2012.vcxproj.filters b/UVAtlasTool/UVAtlasTool_2012.vcxproj.filters new file mode 100644 index 0000000..54027c6 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2012.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {8e114980-c1a3-4ada-ad7c-83caadf5daeb} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {2c3d4c8c-5d1a-459a-a05a-a4e4b608a44e} + fx;fxh;hlsl + + + + + + + + + + + + + + + Resource Files + + + + + \ No newline at end of file diff --git a/UVAtlasTool/UVAtlasTool_2013.sln b/UVAtlasTool/UVAtlasTool_2013.sln new file mode 100644 index 0000000..1d04ca5 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2013.sln @@ -0,0 +1,75 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UVAtlasTool", "UVAtlasTool_2013.vcxproj", "{A7969CB3-E89B-49B9-96E7-8A219785A7CB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXTex", "..\..\DirectXTex\DirectXTex\DirectXTex_Desktop_2013.vcxproj", "{371B9FA9-4C90-4AC6-A123-ACED756D6C77}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXMesh", "..\..\DirectXMesh\DirectXMesh\DirectXMesh_Desktop_2013.vcxproj", "{6857F086-F6FE-4150-9ED7-7446F1C1C220}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UVAtlas_2013", "..\UVAtlas\UVAtlas_2013.vcxproj", "{10359E70-6A7F-4433-8EF1-B0FB688D830E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Profile|Win32 = Profile|Win32 + Profile|x64 = Profile|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|Win32.Build.0 = Debug|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|x64.ActiveCfg = Debug|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Debug|x64.Build.0 = Debug|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|Win32.ActiveCfg = Profile|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|Win32.Build.0 = Profile|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|x64.ActiveCfg = Profile|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Profile|x64.Build.0 = Profile|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|Win32.ActiveCfg = Release|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|Win32.Build.0 = Release|Win32 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|x64.ActiveCfg = Release|x64 + {A7969CB3-E89B-49B9-96E7-8A219785A7CB}.Release|x64.Build.0 = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.ActiveCfg = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|Win32.Build.0 = Debug|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.ActiveCfg = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Debug|x64.Build.0 = Debug|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.ActiveCfg = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|Win32.Build.0 = Profile|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.ActiveCfg = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Profile|x64.Build.0 = Profile|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.ActiveCfg = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|Win32.Build.0 = Release|Win32 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.ActiveCfg = Release|x64 + {371B9FA9-4C90-4AC6-A123-ACED756D6C77}.Release|x64.Build.0 = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.ActiveCfg = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|Win32.Build.0 = Debug|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.ActiveCfg = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Debug|x64.Build.0 = Debug|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.ActiveCfg = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|Win32.Build.0 = Profile|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.ActiveCfg = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Profile|x64.Build.0 = Profile|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.ActiveCfg = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|Win32.Build.0 = Release|Win32 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.ActiveCfg = Release|x64 + {6857F086-F6FE-4150-9ED7-7446F1C1C220}.Release|x64.Build.0 = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|Win32.ActiveCfg = Debug|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|Win32.Build.0 = Debug|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|x64.ActiveCfg = Debug|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Debug|x64.Build.0 = Debug|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|Win32.ActiveCfg = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|Win32.Build.0 = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|x64.ActiveCfg = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Profile|x64.Build.0 = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|Win32.ActiveCfg = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|Win32.Build.0 = Release|Win32 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|x64.ActiveCfg = Release|x64 + {10359E70-6A7F-4433-8EF1-B0FB688D830E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/UVAtlasTool/UVAtlasTool_2013.vcxproj b/UVAtlasTool/UVAtlasTool_2013.vcxproj new file mode 100644 index 0000000..b7a0b44 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2013.vcxproj @@ -0,0 +1,389 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Profile + Win32 + + + Profile + x64 + + + Release + Win32 + + + Release + x64 + + + + UVAtlasTool + {A7969CB3-E89B-49B9-96E7-8A219785A7CB} + UVAtlasTool + Win32Proj + + + + Application + Unicode + v120 + + + Application + Unicode + v120 + + + Application + true + Unicode + v120 + + + Application + true + Unicode + v120 + + + Application + true + Unicode + v120 + + + Application + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + + + + + + true + true + AllRules.ruleset + + + true + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + false + true + AllRules.ruleset + + + + Level4 + Disabled + MultiThreadedDebugDLL + false + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;_DEBUG;DEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + EditAndContinue + EnableFastChecks + + + %(AdditionalOptions) + ole32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + Console + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + Disabled + MultiThreadedDebugDLL + false + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;_DEBUG;DEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + %(AdditionalOptions) + ole32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + Console + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + StreamingSIMDExtensions2 + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX86 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + Level4 + MaxSpeed + MultiThreadedDLL + false + true + true + Fast + Sync + ..\UVAtlas\inc;..\..\DirectXMesh\DirectXMesh;..\..\DirectXMesh\Utilities;..\..\DirectXTex\DirectXTex;%(AdditionalIncludeDirectories) + %(AdditionalOptions) + WIN32;NDEBUG;PROFILE;_CONSOLE;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions) + + + %(AdditionalOptions) + ole32.lib;oleaut32.lib;windowscodecs.lib;uuid.lib;%(AdditionalDependencies) + true + Console + true + true + true + true + true + MachineX64 + AsInvoker + %(DelayLoadDLLs) + + + false + + + + + + + + + + + + + {6857f086-f6fe-4150-9ed7-7446f1c1c220} + + + {371b9fa9-4c90-4ac6-a123-aced756d6c77} + + + {10359e70-6a7f-4433-8ef1-b0fb688d830e} + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UVAtlasTool/UVAtlasTool_2013.vcxproj.filters b/UVAtlasTool/UVAtlasTool_2013.vcxproj.filters new file mode 100644 index 0000000..54027c6 --- /dev/null +++ b/UVAtlasTool/UVAtlasTool_2013.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {8e114980-c1a3-4ada-ad7c-83caadf5daeb} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {2c3d4c8c-5d1a-459a-a05a-a4e4b608a44e} + fx;fxh;hlsl + + + + + + + + + + + + + + + Resource Files + + + + + \ No newline at end of file diff --git a/UVAtlasTool/directx.ico b/UVAtlasTool/directx.ico new file mode 100644 index 0000000..bc43c1b Binary files /dev/null and b/UVAtlasTool/directx.ico differ diff --git a/UVAtlasTool/uvatlas.rc b/UVAtlasTool/uvatlas.rc new file mode 100644 index 0000000..ea1409e --- /dev/null +++ b/UVAtlasTool/uvatlas.rc @@ -0,0 +1,76 @@ +// Microsoft Visual C++ generated resource script. +// +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define IDC_STATIC -1 +#include + + + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAIN_ICON ICON "directx.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define IDC_STATIC -1\r\n" + "#include \r\n" + "\r\n" + "\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED +