Initial population
This commit is contained in:
Родитель
eca6a37bff
Коммит
a629c513d0
|
@ -0,0 +1,375 @@
|
|||
//-------------------------------------------------------------------------------------
|
||||
// DirectXMesh.h
|
||||
//
|
||||
// DirectX Mesh Geometry Library
|
||||
//
|
||||
// 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
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER > 1000)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// VS 2010's stdint.h conflicts with intsafe.h
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#include <stdint.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <d3d11_1.h>
|
||||
#include <directxmath.h>
|
||||
|
||||
#define DIRECTX_MESH_VERSION 001
|
||||
|
||||
namespace DirectX
|
||||
{
|
||||
//---------------------------------------------------------------------------------
|
||||
// DXGI Format Utilities
|
||||
bool IsValidVB( _In_ DXGI_FORMAT fmt );
|
||||
bool IsValidIB( _In_ DXGI_FORMAT fmt );
|
||||
size_t BytesPerElement( _In_ DXGI_FORMAT fmt );
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Input Layout Descriptor Utilities
|
||||
bool IsValid( _In_reads_(nDecl) const D3D11_INPUT_ELEMENT_DESC* vbDecl, _In_ size_t nDecl );
|
||||
void ComputeInputLayout( _In_reads_(nDecl) const D3D11_INPUT_ELEMENT_DESC* vbDecl, _In_ size_t nDecl,
|
||||
_Out_writes_opt_(nDecl) uint32_t* offsets,
|
||||
_Out_writes_opt_(D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT) uint32_t* strides );
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Attribute Utilities
|
||||
std::vector<std::pair<size_t,size_t>> ComputeSubsets( _In_reads_opt_(nFaces) const uint32_t* attributes, _In_ size_t nFaces );
|
||||
// Returns a list of face offset,counts for attribute groups
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Vertex Buffer Reader/Writer
|
||||
|
||||
class VBReader
|
||||
{
|
||||
public:
|
||||
VBReader();
|
||||
VBReader(VBReader&& moveFrom);
|
||||
VBReader& operator= (VBReader&& moveFrom);
|
||||
~VBReader();
|
||||
|
||||
HRESULT Initialize( _In_reads_(nDecl) const D3D11_INPUT_ELEMENT_DESC* vbDecl, _In_ size_t nDecl );
|
||||
// Does not support VB decls with D3D11_INPUT_PER_INSTANCE_DATA
|
||||
|
||||
HRESULT AddStream( _In_reads_bytes_(stride*nVerts) const void* vb, _In_ size_t nVerts, _In_ size_t inputSlot, _In_ size_t stride = 0 );
|
||||
// Add vertex buffer to reader
|
||||
|
||||
HRESULT Read( _Out_writes_(count) XMVECTOR* buffer, _In_z_ LPCSTR semanticName, _In_ UINT semanticIndex, _In_ size_t count ) const;
|
||||
// Extracts data elements from vertex buffer
|
||||
|
||||
void Release();
|
||||
|
||||
private:
|
||||
// Private implementation.
|
||||
class Impl;
|
||||
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
|
||||
// Prevent copying.
|
||||
VBReader(VBReader const&);
|
||||
VBReader& operator= (VBReader const&);
|
||||
};
|
||||
|
||||
class VBWriter
|
||||
{
|
||||
public:
|
||||
VBWriter();
|
||||
VBWriter(VBWriter&& moveFrom);
|
||||
VBWriter& operator= (VBWriter&& moveFrom);
|
||||
~VBWriter();
|
||||
|
||||
HRESULT Initialize( _In_reads_(nDecl) const D3D11_INPUT_ELEMENT_DESC* vbDecl, _In_ size_t nDecl );
|
||||
// Does not support VB decls with D3D11_INPUT_PER_INSTANCE_DATA
|
||||
|
||||
HRESULT AddStream( _Out_writes_bytes_(stride*nVerts) void* vb, _In_ size_t nVerts, _In_ size_t inputSlot, _In_ size_t stride = 0 );
|
||||
// Add vertex buffer to writer
|
||||
|
||||
HRESULT Write( _In_reads_(count) const XMVECTOR* buffer, _In_z_ LPCSTR semanticName, _In_ UINT semanticIndex, _In_ size_t count ) const;
|
||||
// Inserts data elements into vertex buffer
|
||||
|
||||
void Release();
|
||||
|
||||
private:
|
||||
// Private implementation.
|
||||
class Impl;
|
||||
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
|
||||
// Prevent copying.
|
||||
VBWriter(VBWriter const&);
|
||||
VBWriter& operator= (VBWriter const&);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Adjacency Computation
|
||||
|
||||
HRESULT GenerateAdjacencyAndPointReps( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions, _In_ size_t nVerts,
|
||||
_In_ float epsilon,
|
||||
_Out_writes_opt_(nVerts) uint32_t* pointRep,
|
||||
_Out_writes_opt_(nFaces*3) uint32_t* adjacency );
|
||||
HRESULT GenerateAdjacencyAndPointReps( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions, _In_ size_t nVerts,
|
||||
_In_ float epsilon,
|
||||
_Out_writes_opt_(nVerts) uint32_t* pointRep,
|
||||
_Out_writes_opt_(nFaces*3) uint32_t* adjacency );
|
||||
// If pointRep is null, it still generates them internally as they are needed for the final adjacency computation
|
||||
|
||||
HRESULT ConvertPointRepsToAdjacency( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions, _In_ size_t nVerts,
|
||||
_In_reads_opt_(nVerts) const uint32_t* pointRep,
|
||||
_Out_writes_(nFaces*3) uint32_t* adjacency );
|
||||
HRESULT ConvertPointRepsToAdjacency( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions, _In_ size_t nVerts,
|
||||
_In_reads_opt_(nVerts) const uint32_t* pointRep,
|
||||
_Out_writes_(nFaces*3) uint32_t* adjacency );
|
||||
// If pointRep is null, assumes an identity
|
||||
|
||||
HRESULT GenerateGSAdjacency( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const uint32_t* pointRep,
|
||||
_In_reads_(nFaces*3) const uint32_t* adjacency, _In_ size_t nVerts,
|
||||
_Out_writes_(nFaces*6) uint16_t* indicesAdj );
|
||||
HRESULT GenerateGSAdjacency( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const uint32_t* pointRep,
|
||||
_In_reads_(nFaces*3) const uint32_t* adjacency, _In_ size_t nVerts,
|
||||
_Out_writes_(nFaces*6) uint32_t* indicesAdj );
|
||||
// Generates an IB suitable for Geometry Shader using D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Normals, Tangents, and Bi-Tangents Computation
|
||||
|
||||
enum CNORM_FLAGS
|
||||
{
|
||||
CNORM_DEFAULT = 0x0,
|
||||
// Default is to compute normals using weight-by-angle
|
||||
|
||||
CNORM_WEIGHT_BY_AREA = 0x1,
|
||||
// Computes normals using weight-by-area
|
||||
|
||||
CNORM_WEIGHT_EQUAL = 0x2,
|
||||
// Compute normals with equal weights
|
||||
|
||||
CNORM_WIND_CW = 0x4,
|
||||
// Vertices are clock-wise (defaults to CCW)
|
||||
};
|
||||
|
||||
HRESULT ComputeNormals( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions, _In_ size_t nVerts,
|
||||
_In_ DWORD flags,
|
||||
_Out_writes_(nVerts) XMFLOAT3* normals );
|
||||
HRESULT ComputeNormals( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions, _In_ size_t nVerts,
|
||||
_In_ DWORD flags,
|
||||
_Out_writes_(nVerts) XMFLOAT3* normals );
|
||||
// Computes vertex normals
|
||||
|
||||
enum CTF_FLAGS
|
||||
{
|
||||
CTF_DEFAULT = 0x0,
|
||||
// Default is to compute normals using weight-by-angle
|
||||
|
||||
CTF_WEIGHT_BY_AREA = 0x1,
|
||||
// Computes normals using weight-by-area
|
||||
|
||||
CTF_WEIGHT_EQUAL = 0x2,
|
||||
// Compute normals with equal weights
|
||||
|
||||
CTF_WIND_CW = 0x4,
|
||||
// Vertices are clock-wise (defaults to CCW)
|
||||
|
||||
CTF_DONT_ORTHOGONALIZE = 0x10,
|
||||
CTF_ORTHOGONALIZE_FROM_U = 0x20,
|
||||
CTF_ORTHOGONALIZE_FROM_V = 0x40,
|
||||
};
|
||||
|
||||
HRESULT ComputeTangentFrame( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions,
|
||||
_In_reads_(nVerts) const XMFLOAT3* normals,
|
||||
_In_reads_(nVerts) const XMFLOAT2* txtcoords, _In_ size_t nVerts,
|
||||
_In_ DWORD flags,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT3* tangents,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT3* binormals );
|
||||
HRESULT ComputeTangentFrame( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions,
|
||||
_In_reads_(nVerts) const XMFLOAT3* normals,
|
||||
_In_reads_(nVerts) const XMFLOAT2* txtcoords, _In_ size_t nVerts,
|
||||
_In_ DWORD flags,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT3* tangents,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT3* binormals );
|
||||
HRESULT ComputeTangentFrame( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions,
|
||||
_In_reads_(nVerts) const XMFLOAT3* normals,
|
||||
_In_reads_(nVerts) const XMFLOAT2* txtcoords, _In_ size_t nVerts,
|
||||
_In_ DWORD flags,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT4* tangents,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT4* binormals );
|
||||
HRESULT ComputeTangentFrame( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const XMFLOAT3* positions,
|
||||
_In_reads_(nVerts) const XMFLOAT3* normals,
|
||||
_In_reads_(nVerts) const XMFLOAT2* txtcoords, _In_ size_t nVerts,
|
||||
_In_ DWORD flags,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT4* tangents,
|
||||
_Out_writes_opt_(nVerts) XMFLOAT4* binormals );
|
||||
// Computes tangents and/or bi-normals (optionally with handedness stored in .w)
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Mesh clean-up and validation
|
||||
|
||||
enum VALIDATE_FLAGS
|
||||
{
|
||||
VALIDATE_DEFAULT = 0x0,
|
||||
|
||||
VALIDATE_BACKFACING = 0x1,
|
||||
// Check for duplicate neighbor from triangle (requires adjacency)
|
||||
|
||||
VALIDATE_BOWTIES = 0x2,
|
||||
// Check for two fans of triangles using the same vertex (requires adjacency)
|
||||
|
||||
VALIDATE_DEGENERATE = 0x4,
|
||||
// Check for degenerate triangles
|
||||
};
|
||||
|
||||
HRESULT Validate( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_ size_t nVerts, _In_reads_opt_(nFaces*3) const uint32_t* adjacency,
|
||||
_In_ DWORD flags, _In_opt_ std::wstring* msgs = nullptr );
|
||||
HRESULT Validate( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_ size_t nVerts, _In_reads_opt_(nFaces*3) const uint32_t* adjacency,
|
||||
_In_ DWORD flags, _In_opt_ std::wstring* msgs = nullptr );
|
||||
// Checks the mesh for common problems, return 'S_OK' if no problems were found
|
||||
|
||||
HRESULT Clean( _Inout_updates_all_(nFaces*3) uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_ size_t nVerts, _Inout_updates_all_opt_(nFaces*3) uint32_t* adjacency,
|
||||
_In_reads_opt_(nFaces) const uint32_t* attributes,
|
||||
_Inout_ std::vector<uint32_t>& dupVerts, _In_ bool breakBowties=false );
|
||||
HRESULT Clean( _Inout_updates_all_(nFaces*3) uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_ size_t nVerts, _Inout_updates_all_opt_(nFaces*3) uint32_t* adjacency,
|
||||
_In_reads_opt_(nFaces) const uint32_t* attributes,
|
||||
_Inout_ std::vector<uint32_t>& dupVerts, _In_ bool breakBowties=false );
|
||||
// Cleans the mesh, splitting vertices if needed
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Mesh Optimization
|
||||
|
||||
HRESULT AttributeSort( _In_ size_t nFaces, _Inout_updates_all_opt_(nFaces) uint32_t* attributes,
|
||||
_Out_writes_(nFaces) uint32_t* faceRemap );
|
||||
// Reorders faces by attribute id
|
||||
|
||||
enum OPTFACES
|
||||
{
|
||||
OPTFACES_V_DEFAULT = 12,
|
||||
OPTFACES_R_DEFAULT = 7,
|
||||
// Default vertex cache size and restart threshold which is considered 'device independent'
|
||||
|
||||
OPTFACES_V_STRIPORDER = 0,
|
||||
// Indicates no vertex cache optimization, only reordering into strips
|
||||
};
|
||||
|
||||
HRESULT OptimizeFaces( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces*3) const uint32_t* adjacency,
|
||||
_Out_writes_(nFaces) uint32_t* faceRemap,
|
||||
_In_ uint32_t vertexCache = OPTFACES_V_DEFAULT,
|
||||
_In_ uint32_t restart = OPTFACES_R_DEFAULT );
|
||||
HRESULT OptimizeFaces( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces*3) const uint32_t* adjacency,
|
||||
_Out_writes_(nFaces) uint32_t* faceRemap,
|
||||
_In_ uint32_t vertexCache = OPTFACES_V_DEFAULT,
|
||||
_In_ uint32_t restart = OPTFACES_R_DEFAULT );
|
||||
// Reorders faces to increase hit rate of vertex caches
|
||||
|
||||
HRESULT OptimizeFacesEx( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces*3) const uint32_t* adjacency,
|
||||
_In_reads_(nFaces) const uint32_t* attributes,
|
||||
_Out_writes_(nFaces) uint32_t* faceRemap,
|
||||
_In_ uint32_t vertexCache = OPTFACES_V_DEFAULT,
|
||||
_In_ uint32_t restart = OPTFACES_R_DEFAULT );
|
||||
HRESULT OptimizeFacesEx( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces*3) const uint32_t* adjacency,
|
||||
_In_reads_(nFaces) const uint32_t* attributes,
|
||||
_Out_writes_(nFaces) uint32_t* faceRemap,
|
||||
_In_ uint32_t vertexCache = OPTFACES_V_DEFAULT,
|
||||
_In_ uint32_t restart = OPTFACES_R_DEFAULT );
|
||||
// Attribute group version of OptimizeFaces
|
||||
|
||||
HRESULT OptimizeVertices( _In_reads_(nFaces*3) const uint16_t* indices, _In_ size_t nFaces, _In_ size_t nVerts,
|
||||
_Out_writes_(nVerts) uint32_t* vertexRemap );
|
||||
HRESULT OptimizeVertices( _In_reads_(nFaces*3) const uint32_t* indices, _In_ size_t nFaces, _In_ size_t nVerts,
|
||||
_Out_writes_(nVerts) uint32_t* vertexRemap );
|
||||
// Reorders vertices in order of use
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Remap functions
|
||||
|
||||
HRESULT ReorderIB( _In_reads_(nFaces*3) const uint16_t* ibin, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap,
|
||||
_Out_writes_(nFaces*3) uint16_t* ibout );
|
||||
HRESULT ReorderIB( _Inout_updates_all_(nFaces*3) uint16_t* ib, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap );
|
||||
HRESULT ReorderIB( _In_reads_(nFaces*3) const uint32_t* ibin, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap,
|
||||
_Out_writes_(nFaces*3) uint32_t* ibout );
|
||||
HRESULT ReorderIB( _Inout_updates_all_(nFaces*3) uint32_t* ib, _In_ size_t nFaces,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap );
|
||||
// Applies a face remap reordering to an index buffer
|
||||
|
||||
HRESULT ReorderIBAndAdjacency( _In_reads_(nFaces*3) const uint16_t* ibin, _In_ size_t nFaces, _In_reads_(nFaces*3) const uint32_t* adjin,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap,
|
||||
_Out_writes_(nFaces*3) uint16_t* ibout, _Out_writes_(nFaces*3) uint32_t* adjout );
|
||||
HRESULT ReorderIBAndAdjacency( _Inout_updates_all_(nFaces*3) uint16_t* ib, _In_ size_t nFaces, _Inout_updates_all_(nFaces*3) uint32_t* adj,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap );
|
||||
HRESULT ReorderIBAndAdjacency( _In_reads_(nFaces*3) const uint32_t* ibin, _In_ size_t nFaces, _In_reads_(nFaces*3) const uint32_t* adjin,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap,
|
||||
_Out_writes_(nFaces*3) uint32_t* ibout, _Out_writes_(nFaces*3) uint32_t* adjout );
|
||||
HRESULT ReorderIBAndAdjacency( _Inout_updates_all_(nFaces*3) uint32_t* ib, _In_ size_t nFaces, _Inout_updates_all_(nFaces*3) uint32_t* adj,
|
||||
_In_reads_(nFaces) const uint32_t* faceRemap );
|
||||
// Applies a face remap reordering to an index buffer and adjacency
|
||||
|
||||
HRESULT FinalizeIB( _In_reads_(nFaces*3) const uint16_t* ibin, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const uint32_t* vertexRemap, _In_ size_t nVerts,
|
||||
_Out_writes_(nFaces*3) uint16_t* ibout );
|
||||
HRESULT FinalizeIB( _Inout_updates_all_(nFaces*3) uint16_t* ib, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const uint32_t* vertexRemap, _In_ size_t nVerts );
|
||||
HRESULT FinalizeIB( _In_reads_(nFaces*3) const uint32_t* ibin, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const uint32_t* vertexRemap, _In_ size_t nVerts,
|
||||
_Out_writes_(nFaces*3) uint32_t* ibout );
|
||||
HRESULT FinalizeIB( _Inout_updates_all_(nFaces*3) uint32_t* ib, _In_ size_t nFaces,
|
||||
_In_reads_(nVerts) const uint32_t* vertexRemap, _In_ size_t nVerts );
|
||||
// Applies a vertex remap reordering to an index buffer
|
||||
|
||||
HRESULT FinalizeVB( _In_reads_bytes_(nVerts*stride) const void* vbin, _In_ size_t stride, _In_ size_t nVerts,
|
||||
_In_reads_opt_(nDupVerts) const uint32_t* dupVerts, _In_ size_t nDupVerts,
|
||||
_In_reads_opt_(nVerts+nDupVerts) const uint32_t* vertexRemap,
|
||||
_Out_writes_bytes_((nVerts+nDupVerts)*stride) void* vbout );
|
||||
HRESULT FinalizeVB( _Inout_updates_bytes_all_(nVerts*stride) void* vb, _In_ size_t stride, _In_ size_t nVerts,
|
||||
_In_reads_(nVerts) const uint32_t* vertexRemap );
|
||||
// Applies a vertex remap and/or a vertex duplication set to a vertex buffer
|
||||
|
||||
HRESULT FinalizeVBAndPointReps( _In_reads_bytes_(nVerts*stride) const void* vbin, _In_ size_t stride, _In_ size_t nVerts,
|
||||
_In_reads_(nVerts) const uint32_t* prin,
|
||||
_In_reads_opt_(nDupVerts) const uint32_t* dupVerts, _In_ size_t nDupVerts,
|
||||
_In_reads_opt_(nVerts+nDupVerts) const uint32_t* vertexRemap,
|
||||
_Out_writes_bytes_((nVerts+nDupVerts)*stride) void* vbout,
|
||||
_Out_writes_(nVerts+nDupVerts) uint32_t* prout );
|
||||
HRESULT FinalizeVBAndPointReps( _Inout_updates_bytes_all_(nVerts*stride) void* vb, _In_ size_t stride, _In_ size_t nVerts,
|
||||
_Inout_updates_all_(nVerts) uint32_t* pointRep,
|
||||
_In_reads_(nVerts) const uint32_t* vertexRemap );
|
||||
// Applies a vertex remap and/or a vertex duplication set to a vertex buffer and point representatives
|
||||
|
||||
#include "DirectXMesh.inl"
|
||||
|
||||
}; // namespace
|
|
@ -0,0 +1,71 @@
|
|||
//-------------------------------------------------------------------------------------
|
||||
// ACMR.h
|
||||
//
|
||||
// Function for computing the average cache miss ratio for vertex caches
|
||||
//
|
||||
// http://www.realtimerendering.com/blog/acmr-and-atvr/
|
||||
//
|
||||
// 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 <sal.h>
|
||||
#include <stdint.h>
|
||||
|
||||
template<class index_t>
|
||||
void CalculateMissRate( _In_reads_(nFaces*3) const index_t* indices, size_t nFaces, size_t nVerts, size_t cacheSize,
|
||||
float& acmr, float& atvr )
|
||||
{
|
||||
acmr = -1.f;
|
||||
atvr = -1.f;
|
||||
|
||||
if ( !indices || !nFaces || !nVerts || !cacheSize )
|
||||
return;
|
||||
|
||||
if ( ( uint64_t(nFaces) * 3 ) > 0xFFFFFFFF )
|
||||
return;
|
||||
|
||||
size_t misses = 0;
|
||||
|
||||
std::unique_ptr<uint32_t> fifo( new uint32_t[ cacheSize ] );
|
||||
size_t tail = 0;
|
||||
|
||||
memset( fifo.get(), 0xff, sizeof(uint32_t) * cacheSize );
|
||||
|
||||
for( size_t j = 0; j < (nFaces * 3); ++j )
|
||||
{
|
||||
if ( indices[ j ] == index_t(-1) )
|
||||
continue;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for( size_t ptr = 0; ptr < cacheSize; ++ptr )
|
||||
{
|
||||
if ( fifo.get()[ ptr ] == indices[ j ] )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
{
|
||||
++misses;
|
||||
fifo.get()[ tail ] = indices[ j ];
|
||||
++tail;
|
||||
if ( tail == cacheSize ) tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ideal is 0.5, individual tris have 3.0
|
||||
acmr = float( misses ) / float( nFaces );
|
||||
|
||||
// ideal is 1.0, worst case is 6.0
|
||||
atvr = float( misses ) / float( nVerts );
|
||||
}
|
|
@ -0,0 +1,542 @@
|
|||
//--------------------------------------------------------------------------------------
|
||||
// File: WaveFrontReader.h
|
||||
//
|
||||
// Code for loading basic mesh data from a WaveFront OBJ file
|
||||
//
|
||||
// http://en.wikipedia.org/wiki/Wavefront_.obj_file
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// http://go.microsoft.com/fwlink/?LinkID=324981
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#include <stdint.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <directxmath.h>
|
||||
#include <directxcollision.h>
|
||||
|
||||
template<class index_t>
|
||||
class WaveFrontReader
|
||||
{
|
||||
public:
|
||||
typedef index_t index_t;
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
DirectX::XMFLOAT3 position;
|
||||
DirectX::XMFLOAT3 normal;
|
||||
DirectX::XMFLOAT2 textureCoordinate;
|
||||
};
|
||||
|
||||
WaveFrontReader() : hasNormals(false), hasTexcoords(false) {}
|
||||
|
||||
HRESULT Load( _In_z_ const wchar_t* szFileName, bool ccw = true )
|
||||
{
|
||||
Clear();
|
||||
|
||||
static const size_t MAX_POLY = 64;
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
std::wifstream InFile( szFileName );
|
||||
if( !InFile )
|
||||
return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
||||
|
||||
WCHAR fname[_MAX_FNAME];
|
||||
_wsplitpath_s( szFileName, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, nullptr, 0 );
|
||||
|
||||
name = fname;
|
||||
|
||||
std::vector<XMFLOAT3> positions;
|
||||
std::vector<XMFLOAT3> normals;
|
||||
std::vector<XMFLOAT2> texCoords;
|
||||
|
||||
VertexCache vertexCache;
|
||||
|
||||
Material defmat;
|
||||
|
||||
wcscpy_s( defmat.strName, L"default" );
|
||||
materials.push_back( defmat );
|
||||
|
||||
uint32_t curSubset = 0;
|
||||
|
||||
WCHAR strCommand[256] = {0};
|
||||
WCHAR strMaterialFilename[MAX_PATH] = {0};
|
||||
for( ;; )
|
||||
{
|
||||
InFile >> strCommand;
|
||||
if( !InFile )
|
||||
break;
|
||||
|
||||
if( 0 == wcscmp( strCommand, L"#" ) )
|
||||
{
|
||||
// Comment
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"v" ) )
|
||||
{
|
||||
// Vertex Position
|
||||
float x, y, z;
|
||||
InFile >> x >> y >> z;
|
||||
positions.push_back( XMFLOAT3( x, y, z ) );
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"vt" ) )
|
||||
{
|
||||
// Vertex TexCoord
|
||||
float u, v;
|
||||
InFile >> u >> v;
|
||||
texCoords.push_back( XMFLOAT2( u, v ) );
|
||||
|
||||
hasTexcoords = true;
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"vn" ) )
|
||||
{
|
||||
// Vertex Normal
|
||||
float x, y, z;
|
||||
InFile >> x >> y >> z;
|
||||
normals.push_back( XMFLOAT3( x, y, z ) );
|
||||
|
||||
hasNormals = true;
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"f" ) )
|
||||
{
|
||||
// Face
|
||||
UINT iPosition, iTexCoord, iNormal;
|
||||
Vertex vertex;
|
||||
|
||||
DWORD faceIndex[ MAX_POLY ];
|
||||
size_t iFace = 0;
|
||||
for(;;)
|
||||
{
|
||||
if ( iFace >= MAX_POLY )
|
||||
{
|
||||
// Too many polygon verts for the reader
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
memset( &vertex, 0, sizeof( vertex ) );
|
||||
|
||||
// OBJ format uses 1-based arrays
|
||||
InFile >> iPosition;
|
||||
if ( iPosition > positions.size() )
|
||||
return E_FAIL;
|
||||
|
||||
vertex.position = positions[ iPosition - 1 ];
|
||||
|
||||
if( '/' == InFile.peek() )
|
||||
{
|
||||
InFile.ignore();
|
||||
|
||||
if( '/' != InFile.peek() )
|
||||
{
|
||||
// Optional texture coordinate
|
||||
InFile >> iTexCoord;
|
||||
if ( iTexCoord > texCoords.size() )
|
||||
return E_FAIL;
|
||||
|
||||
vertex.textureCoordinate = texCoords[ iTexCoord - 1 ];
|
||||
}
|
||||
|
||||
if( '/' == InFile.peek() )
|
||||
{
|
||||
InFile.ignore();
|
||||
|
||||
// Optional vertex normal
|
||||
InFile >> iNormal;
|
||||
if ( iNormal > normals.size() )
|
||||
return E_FAIL;
|
||||
|
||||
vertex.normal = normals[ iNormal - 1 ];
|
||||
}
|
||||
}
|
||||
|
||||
// If a duplicate vertex doesn't exist, add this vertex to the Vertices
|
||||
// list. Store the index in the Indices array. The Vertices and Indices
|
||||
// lists will eventually become the Vertex Buffer and Index Buffer for
|
||||
// the mesh.
|
||||
DWORD index = AddVertex( iPosition, &vertex, vertexCache );
|
||||
if ( index == (DWORD)-1 )
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
#pragma warning( suppress : 4127 )
|
||||
if ( sizeof(index_t) == 2 && ( index >= 0xFFFF ) )
|
||||
{
|
||||
// Too many indices for 16-bit IB!
|
||||
return E_FAIL;
|
||||
}
|
||||
else if ( sizeof(index_t) == 4 && ( index >= 0xFFFFFFFF ) )
|
||||
{
|
||||
// Too many indices for 32-bit IB!
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
faceIndex[ iFace ] = index;
|
||||
++iFace;
|
||||
|
||||
// Check for more face data or end of the face statement
|
||||
bool faceEnd = false;
|
||||
for(;;)
|
||||
{
|
||||
wchar_t p = InFile.peek();
|
||||
|
||||
if ( '\n' == p || !InFile )
|
||||
{
|
||||
faceEnd = true;
|
||||
break;
|
||||
}
|
||||
else if ( isdigit( p ) )
|
||||
break;
|
||||
|
||||
InFile.ignore();
|
||||
}
|
||||
|
||||
if ( faceEnd )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( iFace < 3 )
|
||||
{
|
||||
// Need at least 3 points to form a triangle
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Convert polygons to triangles
|
||||
DWORD i0 = faceIndex[0];
|
||||
DWORD i1 = faceIndex[1];
|
||||
|
||||
for( size_t j = 2; j < iFace; ++ j )
|
||||
{
|
||||
DWORD index = faceIndex[ j ];
|
||||
indices.push_back( static_cast<uint16_t>( i0 ) );
|
||||
if ( ccw )
|
||||
{
|
||||
indices.push_back( static_cast<uint16_t>( i1 ) );
|
||||
indices.push_back( static_cast<uint16_t>( index ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
indices.push_back( static_cast<uint16_t>( index ) );
|
||||
indices.push_back( static_cast<uint16_t>( i1 ) );
|
||||
}
|
||||
|
||||
attributes.push_back( curSubset );
|
||||
|
||||
i1 = index;
|
||||
}
|
||||
|
||||
assert( attributes.size()*3 == indices.size() );
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"mtllib" ) )
|
||||
{
|
||||
// Material library
|
||||
InFile >> strMaterialFilename;
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"usemtl" ) )
|
||||
{
|
||||
// Material
|
||||
WCHAR strName[MAX_PATH] = {0};
|
||||
InFile >> strName;
|
||||
|
||||
bool bFound = false;
|
||||
uint32_t count = 0;
|
||||
for( auto it = materials.cbegin(); it != materials.cend(); ++it, ++count )
|
||||
{
|
||||
if( 0 == wcscmp( it->strName, strName ) )
|
||||
{
|
||||
bFound = true;
|
||||
curSubset = count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !bFound )
|
||||
{
|
||||
Material mat;
|
||||
curSubset = static_cast<uint32_t>( materials.size() );
|
||||
wcscpy_s( mat.strName, MAX_PATH - 1, strName );
|
||||
materials.push_back( mat );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unimplemented or unrecognized command
|
||||
OutputDebugStringW( strCommand );
|
||||
}
|
||||
|
||||
InFile.ignore( 1000, '\n' );
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
InFile.close();
|
||||
|
||||
BoundingBox::CreateFromPoints( bounds, positions.size(), &positions.front(), sizeof(XMFLOAT3) );
|
||||
|
||||
// If an associated material file was found, read that in as well.
|
||||
if( *strMaterialFilename )
|
||||
{
|
||||
WCHAR ext[_MAX_EXT];
|
||||
_wsplitpath_s( strMaterialFilename, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT );
|
||||
|
||||
WCHAR drive[_MAX_DRIVE];
|
||||
WCHAR dir[_MAX_DIR];
|
||||
_wsplitpath_s( szFileName, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0 );
|
||||
|
||||
WCHAR szPath[ MAX_PATH ];
|
||||
_wmakepath_s( szPath, MAX_PATH, drive, dir, fname, ext );
|
||||
|
||||
HRESULT hr = LoadMTL( szPath );
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT LoadMTL( _In_z_ const wchar_t* szFileName )
|
||||
{
|
||||
// Assumes MTL is in CWD along with OBJ
|
||||
std::wifstream InFile( szFileName );
|
||||
if( !InFile )
|
||||
return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
||||
|
||||
auto curMaterial = materials.end();
|
||||
|
||||
WCHAR strCommand[256] = {0};
|
||||
for( ;; )
|
||||
{
|
||||
InFile >> strCommand;
|
||||
if( !InFile )
|
||||
break;
|
||||
|
||||
if( 0 == wcscmp( strCommand, L"newmtl" ) )
|
||||
{
|
||||
// Switching active materials
|
||||
WCHAR strName[MAX_PATH] = {0};
|
||||
InFile >> strName;
|
||||
|
||||
curMaterial = materials.end();
|
||||
for( auto it = materials.begin(); it != materials.end(); ++it )
|
||||
{
|
||||
if( 0 == wcscmp( it->strName, strName ) )
|
||||
{
|
||||
curMaterial = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of the commands rely on an active material
|
||||
if( curMaterial == materials.end() )
|
||||
continue;
|
||||
|
||||
if( 0 == wcscmp( strCommand, L"#" ) )
|
||||
{
|
||||
// Comment
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"Ka" ) )
|
||||
{
|
||||
// Ambient color
|
||||
float r, g, b;
|
||||
InFile >> r >> g >> b;
|
||||
curMaterial->vAmbient = XMFLOAT3( r, g, b );
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"Kd" ) )
|
||||
{
|
||||
// Diffuse color
|
||||
float r, g, b;
|
||||
InFile >> r >> g >> b;
|
||||
curMaterial->vDiffuse = XMFLOAT3( r, g, b );
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"Ks" ) )
|
||||
{
|
||||
// Specular color
|
||||
float r, g, b;
|
||||
InFile >> r >> g >> b;
|
||||
curMaterial->vSpecular = XMFLOAT3( r, g, b );
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"d" ) ||
|
||||
0 == wcscmp( strCommand, L"Tr" ) )
|
||||
{
|
||||
// Alpha
|
||||
InFile >> curMaterial->fAlpha;
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"Ns" ) )
|
||||
{
|
||||
// Shininess
|
||||
int nShininess;
|
||||
InFile >> nShininess;
|
||||
curMaterial->nShininess = nShininess;
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"illum" ) )
|
||||
{
|
||||
// Specular on/off
|
||||
int illumination;
|
||||
InFile >> illumination;
|
||||
curMaterial->bSpecular = ( illumination == 2 );
|
||||
}
|
||||
else if( 0 == wcscmp( strCommand, L"map_Kd" ) )
|
||||
{
|
||||
// Texture
|
||||
InFile >> curMaterial->strTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unimplemented or unrecognized command
|
||||
}
|
||||
|
||||
InFile.ignore( 1000, L'\n' );
|
||||
}
|
||||
|
||||
InFile.close();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
attributes.clear();
|
||||
materials.clear();
|
||||
name.clear();
|
||||
hasNormals = false;
|
||||
hasTexcoords = false;
|
||||
|
||||
bounds.Center.x = bounds.Center.y = bounds.Center.z = 0.f;
|
||||
bounds.Extents.x = bounds.Extents.y = bounds.Extents.z = 0.f;
|
||||
}
|
||||
|
||||
HRESULT LoadVBO( _In_z_ const wchar_t* szFileName )
|
||||
{
|
||||
Clear();
|
||||
|
||||
WCHAR fname[_MAX_FNAME];
|
||||
_wsplitpath_s( szFileName, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, nullptr, 0 );
|
||||
|
||||
name = fname;
|
||||
|
||||
Material defmat;
|
||||
wcscpy_s( defmat.strName, L"default" );
|
||||
materials.push_back( defmat );
|
||||
|
||||
std::ifstream vboFile(szFileName, std::ifstream::in | std::ifstream::binary);
|
||||
if ( !vboFile.is_open() )
|
||||
return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
||||
|
||||
hasNormals = hasTexcoords = true;
|
||||
|
||||
uint32_t numVertices = 0;
|
||||
uint32_t numIndices = 0;
|
||||
|
||||
vboFile.read( reinterpret_cast<char*>( &numVertices ), sizeof(uint32_t ) );
|
||||
if ( !numVertices )
|
||||
return E_FAIL;
|
||||
|
||||
vboFile.read( reinterpret_cast<char*>( &numIndices ), sizeof(uint32_t ) );
|
||||
if ( !numIndices )
|
||||
return E_FAIL;
|
||||
|
||||
vertices.resize( numVertices );
|
||||
vboFile.read( reinterpret_cast<char*>( &vertices.front() ), sizeof(Vertex) * numVertices );
|
||||
|
||||
#pragma warning( suppress : 4127 )
|
||||
if ( sizeof( index_t ) == 2 )
|
||||
{
|
||||
indices.resize( numIndices );
|
||||
vboFile.read( reinterpret_cast<char*>( &indices.front() ), sizeof(uint16_t) * numIndices );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<uint16_t> tmp;
|
||||
tmp.resize( numIndices );
|
||||
vboFile.read( reinterpret_cast<char*>( &tmp.front() ), sizeof(uint16_t) * numIndices );
|
||||
|
||||
indices.reserve( numIndices );
|
||||
for( auto it = tmp.cbegin(); it != tmp.cend(); ++it )
|
||||
{
|
||||
indices.push_back( *it );
|
||||
}
|
||||
}
|
||||
|
||||
BoundingBox::CreateFromPoints( bounds, vertices.size(), reinterpret_cast<const XMFLOAT3*>( &vertices.front() ), sizeof(Vertex) );
|
||||
|
||||
vboFile.close();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
struct Material
|
||||
{
|
||||
DirectX::XMFLOAT3 vAmbient;
|
||||
DirectX::XMFLOAT3 vDiffuse;
|
||||
DirectX::XMFLOAT3 vSpecular;
|
||||
uint32_t nShininess;
|
||||
float fAlpha;
|
||||
|
||||
bool bSpecular;
|
||||
|
||||
WCHAR strName[MAX_PATH];
|
||||
WCHAR strTexture[MAX_PATH];
|
||||
|
||||
Material() :
|
||||
vAmbient( 0.2f, 0.2f, 0.2f ),
|
||||
vDiffuse( 0.8f, 0.8f, 0.8f ),
|
||||
vSpecular( 1.0f, 1.0f, 1.0f ),
|
||||
nShininess( 0 ),
|
||||
fAlpha( 1.f ),
|
||||
bSpecular( false )
|
||||
{ memset(strName, 0, MAX_PATH); memset(strTexture, 0, MAX_PATH); }
|
||||
};
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<index_t> indices;
|
||||
std::vector<uint32_t> attributes;
|
||||
std::vector<Material> materials;
|
||||
|
||||
std::wstring name;
|
||||
bool hasNormals;
|
||||
bool hasTexcoords;
|
||||
|
||||
DirectX::BoundingBox bounds;
|
||||
|
||||
private:
|
||||
typedef std::unordered_multimap<UINT, UINT> VertexCache;
|
||||
|
||||
DWORD AddVertex( UINT hash, Vertex* pVertex, VertexCache& cache )
|
||||
{
|
||||
auto f = cache.equal_range( hash );
|
||||
|
||||
for( auto it = f.first; it != f.second; ++it )
|
||||
{
|
||||
auto& tv = vertices[ it->second ];
|
||||
|
||||
if ( 0 == memcmp( pVertex, &tv, sizeof(Vertex) ) )
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD index = static_cast<UINT>( vertices.size() );
|
||||
vertices.push_back( *pVertex );
|
||||
|
||||
VertexCache::value_type entry( hash, index );
|
||||
cache.insert( entry );
|
||||
return index;
|
||||
}
|
||||
};
|
Загрузка…
Ссылка в новой задаче