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;
|
||||||
|
}
|
||||||
|
};
|
Загрузка…
Ссылка в новой задаче