//-------------------------------------------------------------------------------------- // File: ModelLoadVBO.cpp // // 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=248929 //-------------------------------------------------------------------------------------- #include "pch.h" #include "Model.h" #include "Effects.h" #include "VertexTypes.h" #include "DirectXHelpers.h" #include "PlatformHelpers.h" #include "BinaryReader.h" using namespace DirectX; using Microsoft::WRL::ComPtr; //-------------------------------------------------------------------------------------- // The VBO file format was introduced in the Windows 8.0 ResourceLoading sample. It's // a simple binary file containing a 16-bit index buffer and a fixed-format vertex buffer. // // The meshconvert sample tool for DirectXMesh can produce this file type // http://go.microsoft.com/fwlink/?LinkID=324981 //-------------------------------------------------------------------------------------- namespace VBO { #pragma pack(push,1) struct header_t { uint32_t numVertices; uint32_t numIndices; }; #pragma pack(pop) }; // namespace static_assert(sizeof(VBO::header_t) == 8, "VBO header size mismatch"); static_assert(sizeof(VertexPositionNormalTexture) == 32, "VBO vertex size mismatch"); //-------------------------------------------------------------------------------------- // Shared VB input element description static INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT; static std::shared_ptr> g_vbdecl; static BOOL CALLBACK InitializeDecl(PINIT_ONCE initOnce, PVOID Parameter, PVOID *lpContext) { UNREFERENCED_PARAMETER(initOnce); UNREFERENCED_PARAMETER(Parameter); UNREFERENCED_PARAMETER(lpContext); g_vbdecl = std::make_shared>(VertexPositionNormalTexture::InputElements, VertexPositionNormalTexture::InputElements + VertexPositionNormalTexture::InputElementCount); return TRUE; } //-------------------------------------------------------------------------------------- _Use_decl_annotations_ std::unique_ptr DirectX::Model::CreateFromVBO(ID3D11Device* d3dDevice, const uint8_t* meshData, size_t dataSize, std::shared_ptr ieffect, bool ccw, bool pmalpha) { if (!InitOnceExecuteOnce(&g_InitOnce, InitializeDecl, nullptr, nullptr)) throw std::exception("One-time initialization failed"); if ( !d3dDevice || !meshData ) throw std::exception("Device and meshData cannot be null"); // File Header if ( dataSize < sizeof(VBO::header_t) ) throw std::exception("End of file"); auto header = reinterpret_cast( meshData ); if ( !header->numVertices || !header->numIndices ) throw std::exception("No vertices or indices found"); size_t vertSize = sizeof(VertexPositionNormalTexture) * header->numVertices; if (dataSize < (vertSize + sizeof(VBO::header_t))) throw std::exception("End of file"); auto verts = reinterpret_cast( meshData + sizeof(VBO::header_t) ); size_t indexSize = sizeof(uint16_t) * header->numIndices; if (dataSize < (sizeof(VBO::header_t) + vertSize + indexSize)) throw std::exception("End of file"); auto indices = reinterpret_cast( meshData + sizeof(VBO::header_t) + vertSize ); // Create vertex buffer ComPtr vb; { D3D11_BUFFER_DESC desc = { 0 }; desc.Usage = D3D11_USAGE_DEFAULT; desc.ByteWidth = static_cast(vertSize); desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA initData = { 0 }; initData.pSysMem = verts; ThrowIfFailed( d3dDevice->CreateBuffer(&desc, &initData, vb.GetAddressOf()) ); SetDebugObjectName(vb.Get(), "ModelVBO"); } // Create index buffer ComPtr ib; { D3D11_BUFFER_DESC desc = { 0 }; desc.Usage = D3D11_USAGE_DEFAULT; desc.ByteWidth = static_cast(indexSize); desc.BindFlags = D3D11_BIND_INDEX_BUFFER; D3D11_SUBRESOURCE_DATA initData = { 0 }; initData.pSysMem = indices; ThrowIfFailed( d3dDevice->CreateBuffer(&desc, &initData, ib.GetAddressOf()) ); SetDebugObjectName(ib.Get(), "ModelVBO"); } // Create input layout and effect if (!ieffect) { auto effect = std::make_shared(d3dDevice); effect->EnableDefaultLighting(); effect->SetLightingEnabled(true); ieffect = effect; } ComPtr il; { void const* shaderByteCode; size_t byteCodeLength; ieffect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength); ThrowIfFailed( d3dDevice->CreateInputLayout(VertexPositionNormalTexture::InputElements, VertexPositionNormalTexture::InputElementCount, shaderByteCode, byteCodeLength, il.GetAddressOf())); SetDebugObjectName(il.Get(), "ModelVBO"); } auto part = new ModelMeshPart(); part->indexCount = header->numIndices; part->startIndex = 0; part->vertexStride = static_cast( sizeof(VertexPositionNormalTexture) ); part->inputLayout = il; part->indexBuffer = ib; part->vertexBuffer = vb; part->effect = ieffect; part->vbDecl = g_vbdecl; auto mesh = std::make_shared(); mesh->ccw = ccw; mesh->pmalpha = pmalpha; BoundingSphere::CreateFromPoints(mesh->boundingSphere, header->numVertices, &verts->position, sizeof(VertexPositionNormalTexture)); BoundingBox::CreateFromPoints(mesh->boundingBox, header->numVertices, &verts->position, sizeof(VertexPositionNormalTexture)); mesh->meshParts.emplace_back(part); std::unique_ptr model(new Model()); model->meshes.emplace_back(mesh); return model; } //-------------------------------------------------------------------------------------- _Use_decl_annotations_ std::unique_ptr DirectX::Model::CreateFromVBO(ID3D11Device* d3dDevice, const wchar_t* szFileName, std::shared_ptr ieffect, bool ccw, bool pmalpha) { size_t dataSize = 0; std::unique_ptr data; HRESULT hr = BinaryReader::ReadEntireFile( szFileName, data, &dataSize ); if ( FAILED(hr) ) { DebugTrace( "CreateFromVBO failed (%08X) loading '%ls'\n", hr, szFileName ); throw std::exception( "CreateFromVBO" ); } auto model = CreateFromVBO( d3dDevice, data.get(), dataSize, ieffect, ccw, pmalpha ); model->name = szFileName; return model; }