static string GetExpandedShaderCode(const wchar* path, GrowableList<wstring>& filePaths) { for(uint64 i = 0; i < filePaths.Count(); ++i) if(filePaths[i] == path) return string(); filePaths.Add(path); string fileContents = ReadFileAsString(path); // Look for includes size_t lineStart = 0; while(true) { size_t lineEnd = fileContents.find('\n', lineStart); size_t lineLength = 0; if(lineEnd == string::npos) lineLength = string::npos; else lineLength = lineEnd - lineStart; string line = fileContents.substr(lineStart, lineLength); if(line.find("#include") == 0) { wstring fullIncludePath; size_t startQuote = line.find('\"'); if(startQuote != -1) { size_t endQuote = line.find('\"', startQuote + 1); string includePath = line.substr(startQuote + 1, endQuote - startQuote - 1); fullIncludePath = AnsiToWString(includePath.c_str()); } else { startQuote = line.find('<'); if(startQuote == -1) throw Exception(L"Malformed include statement: \"" + AnsiToWString(line.c_str()) + L"\" in file " + path); size_t endQuote = line.find('>', startQuote + 1); string includePath = line.substr(startQuote + 1, endQuote - startQuote - 1); fullIncludePath = SampleFrameworkDir() + L"Shaders\\" + AnsiToWString(includePath.c_str()); } if(FileExists(fullIncludePath.c_str()) == false) throw Exception(L"Couldn't find #included file \"" + fullIncludePath + L"\" in file " + path); string includeCode = GetExpandedShaderCode(fullIncludePath.c_str(), filePaths); fileContents.insert(lineEnd + 1, includeCode); lineEnd += includeCode.length(); } if(lineEnd == string::npos) break; lineStart = lineEnd + 1; } return fileContents; }
void Model::CreateFromXFile(ID3D11Device* device, LPCWSTR fileName, const WCHAR* normalMapSuffix, bool generateNormals, bool generateTangentFrame, Mesh::IndexType idxType) { _ASSERT(FileExists(fileName)); IDirect3DDevice9Ptr d3d9Device = CreateD3D9Device(); // Load the D3DX mesh ID3DXMesh* d3dxMesh = NULL; ID3DXBuffer* adjacencyBuffer = NULL; ID3DXBuffer* materialsBuffer = NULL; DWORD numMaterials = 0; UINT options = D3DXMESH_MANAGED; if (idxType == Mesh::Index32Bit) options |= D3DXMESH_32BIT; DXCall(D3DXLoadMeshFromXW(fileName, options, d3d9Device, &adjacencyBuffer, &materialsBuffer, NULL, &numMaterials, &d3dxMesh)); IUnknownReleaser<ID3DXMesh> meshReleaser(d3dxMesh); IUnknownReleaser<ID3DXBuffer> adjReleaser(adjacencyBuffer); IUnknownReleaser<ID3DXBuffer> matReleaser(materialsBuffer); DWORD* initalAdjacency = reinterpret_cast<DWORD*>(adjacencyBuffer->GetBufferPointer()); D3DXMATERIAL* materials = reinterpret_cast<D3DXMATERIAL*>(materialsBuffer->GetBufferPointer()); // Get the directory the mesh was loaded from wstring fileDirectory = GetDirectoryFromFileName(fileName); // Convert materials for (UINT i = 0; i < numMaterials; ++i) { MeshMaterial material; D3DXMATERIAL& srcMaterial = materials[i]; material.AmbientAlbedo = XMFLOAT3(reinterpret_cast<float*>(&srcMaterial.MatD3D.Ambient)); material.DiffuseAlbedo = XMFLOAT3(reinterpret_cast<float*>(&srcMaterial.MatD3D.Diffuse)); material.SpecularAlbedo = XMFLOAT3(reinterpret_cast<float*>(&srcMaterial.MatD3D.Specular)); material.Emissive = XMFLOAT3(reinterpret_cast<float*>(&srcMaterial.MatD3D.Emissive)); material.SpecularPower = srcMaterial.MatD3D.Power; material.Alpha = srcMaterial.MatD3D.Diffuse.a; material.DiffuseMapName = AnsiToWString(srcMaterial.pTextureFilename); // Add the normal map prefix if (normalMapSuffix && material.DiffuseMapName.length() > 0) { wstring base = GetFileNameWithoutExtension(material.DiffuseMapName.c_str()); wstring extension = GetFileExtension(material.DiffuseMapName.c_str()); material.NormalMapName = base + normalMapSuffix + L"." + extension; } LoadMaterialResources(material, fileDirectory, device); } // Make a single mesh Mesh mesh; mesh.CreateFromD3DXMesh(fileDirectory, device, d3d9Device, d3dxMesh, generateNormals, generateTangentFrame, initalAdjacency, idxType); meshes.push_back(mesh); }
HRESULT Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) override { std::wstring filePath; if(IncludeType == D3D_INCLUDE_LOCAL) filePath = AnsiToWString(pFileName); else if(IncludeType == D3D_INCLUDE_SYSTEM) filePath = SampleFrameworkDir() + L"Shaders\\" + AnsiToWString(pFileName); else return E_FAIL; if(FileExists(filePath.c_str()) == false) return E_FAIL; File file(filePath.c_str(), FileOpenMode::Read); *pBytes = UINT(file.Size()); uint8* data = reinterpret_cast<uint8*>(std::malloc(*pBytes)); file.Read(*pBytes, data); *ppData = data; return S_OK; }
HRESULT GeometryShaderLoader::GenerateContentHash(const WCHAR* path, GeometryShaderOptions* options, ContentHash* hash) { if (!hash) { return E_FAIL; } ContentHash retHash; retHash.append(path); if (options) { WCHAR wBuff[1024]; AnsiToWString(options->EntryPoint, wBuff, 1024); retHash.append(wBuff); if (options->Defines) { UINT defineIdx = 0; while (options->Defines[defineIdx].Name) { AnsiToWString(options->Defines[defineIdx].Name, wBuff, 1024); retHash.append(wBuff); AnsiToWString(options->Defines[defineIdx].Definition, wBuff, 1024); retHash.append(wBuff); defineIdx++; } } // Not hashing the debug name since it does not affect the content that is loaded } *hash = retHash; return S_OK; }
HRESULT GeometryShaderLoader::CompileContentFile( ID3D11Device* device, ID3DX11ThreadPump* threadPump, const WCHAR* path, GeometryShaderOptions* options, WCHAR* errorMsg, UINT errorLen, std::ostream* output ) { if (!options) { swprintf_s(errorMsg, errorLen, L"Options cannot be null when loading shaders."); return E_FAIL; } WCHAR logMsg[MAX_LOG_LENGTH]; if (options->DebugName) { WCHAR debugNameW[256]; AnsiToWString(options->DebugName, debugNameW, 256); swprintf_s(logMsg, L"Loading - %s (path = %s)", debugNameW, path); } else { swprintf_s(logMsg, L"Loading - %s", path); } LOG_INFO(L"Pixel Shader Loader", logMsg); HRESULT hr; ID3DBlob* pShaderBlob = NULL; hr = CompileShaderFromFile(path, options->EntryPoint, "gs_5_0", options->Defines, threadPump, errorMsg, errorLen, &pShaderBlob, NULL); if (FAILED(hr)) { // CompileShaderFromFile sets the error message SAFE_RELEASE(pShaderBlob); return hr; } UINT size = pShaderBlob->GetBufferSize(); if (!output->write((const char*)&size, sizeof(UINT))) { return E_FAIL; } if (!output->write((const char*)pShaderBlob->GetBufferPointer(), size)) { return E_FAIL; } return S_OK; }
static string GetExpandedShaderCode(const wchar* path, vector<wstring>& filePaths) { for(uint64 i = 0; i < filePaths.size(); ++i) if(filePaths[i] == path) throw Exception(L"File \"" + wstring(path) + L" is recursively included"); filePaths.push_back(path); string fileContents = ReadFileAsString(path); wstring fileDirectory = GetDirectoryFromFilePath(path); // Look for includes size_t lineStart = 0; size_t lineEnd = std::string::npos; while(true) { size_t lineEnd = fileContents.find('\n', lineStart); size_t lineLength = 0; if(lineEnd == string::npos) lineLength = string::npos; else lineLength = lineEnd - lineStart; string line = fileContents.substr(lineStart, lineLength); if(line.find("#include") == 0) { size_t startQuote = line.find('\"'); size_t endQuote = line.find('\"', startQuote + 1); string includePath = line.substr(startQuote + 1, endQuote - startQuote - 1); wstring fullIncludePath = fileDirectory + AnsiToWString(includePath.c_str()); if(FileExists(fullIncludePath.c_str()) == false) throw Exception(L"Couldn't find #included file \"" + fullIncludePath + L"\""); string includeCode = GetExpandedShaderCode(fullIncludePath.c_str(), filePaths); fileContents.insert(lineEnd + 1, includeCode); lineEnd += includeCode.length(); } if(lineEnd == string::npos) break; lineStart = lineEnd + 1; } return fileContents; }
void SaveTextureAsEXR(const TextureData<Float4>& texture, const wchar* filePath) { Assert_(texture.Texels.size() > 0); Assert_(texture.Width > 0 && texture.Height > 0); Assert_(texture.NumSlices == 1); const uint64 numTexels = texture.Texels.size(); std::vector<float> channelDataR; std::vector<float> channelDataG; std::vector<float> channelDataB; channelDataR.resize(numTexels); channelDataG.resize(numTexels); channelDataB.resize(numTexels); for(uint64 i = 0; i < numTexels; ++i) { channelDataR[i] = texture.Texels[i].x; channelDataG[i] = texture.Texels[i].y; channelDataB[i] = texture.Texels[i].z; } float* imageChannels[3] = { channelDataB.data(), channelDataG.data(), channelDataR.data() }; const char* channelNames[3] = { "B", "G", "R" }; EXRImage exrImage; exrImage.num_channels = 3; exrImage.width = texture.Width; exrImage.height = texture.Height; exrImage.channel_names = channelNames; exrImage.images = imageChannels; std::string filePathAnsi = WStringToAnsi(filePath); const char* errorString = nullptr; int returnCode = SaveMultiChannelEXR(&exrImage, filePathAnsi.c_str(), &errorString); if(returnCode != 0) { AssertFail_("%s", errorString); throw Exception(AnsiToWString(errorString)); } }
void Model::CreateFromSDKMeshFile(ID3D11Device* device, LPCWSTR fileName) { _ASSERT(FileExists(fileName)); // Use the SDKMesh class to load in the data SDKMesh sdkMesh; sdkMesh.Create(fileName); wstring directory = GetDirectoryFromFileName(fileName); // Make materials UINT numMaterials = sdkMesh.GetNumMaterials(); for (UINT i = 0; i < numMaterials; ++i) { MeshMaterial material; SDKMESH_MATERIAL* mat = sdkMesh.GetMaterial(i); memcpy(&material.AmbientAlbedo, &mat->Ambient, sizeof(D3DXVECTOR4)); memcpy(&material.DiffuseAlbedo, &mat->Diffuse, sizeof(D3DXVECTOR4)); memcpy(&material.SpecularAlbedo, &mat->Specular, sizeof(D3DXVECTOR4)); memcpy(&material.Emissive, &mat->Emissive, sizeof(D3DXVECTOR4)); material.Alpha = mat->Diffuse.w; material.SpecularPower = mat->Power; material.DiffuseMapName = AnsiToWString(mat->DiffuseTexture); material.NormalMapName = AnsiToWString(mat->NormalTexture); LoadMaterialResources(material, directory, device); meshMaterials.push_back(material); } // Make a D3D9 device IDirect3DDevice9Ptr d3d9Device = CreateD3D9Device(); UINT numMeshes = sdkMesh.GetNumMeshes(); for (UINT meshIdx = 0; meshIdx < numMeshes; ++meshIdx) { // Figure out the index type UINT ops = D3DXMESH_MANAGED; UINT indexSize = 2; Mesh::IndexType indexType = Mesh::Index16Bit; if (sdkMesh.GetIndexType(meshIdx) == IT_32BIT) { ops |= D3DXMESH_32BIT; indexSize = 4; indexType = Mesh::Index32Bit; } // Make a D3DX mesh ID3DXMesh* d3dxMesh = NULL; UINT numPrims = static_cast<UINT>(sdkMesh.GetNumIndices(meshIdx) / 3); UINT numVerts = static_cast<UINT>(sdkMesh.GetNumVertices(meshIdx, 0)); UINT vbIndex = sdkMesh.GetMesh(meshIdx)->VertexBuffers[0]; UINT ibIndex = sdkMesh.GetMesh(meshIdx)->IndexBuffer; const D3DVERTEXELEMENT9* vbElements = sdkMesh.VBElements(vbIndex); DXCall(D3DXCreateMesh(numPrims, numVerts, ops, vbElements, d3d9Device, &d3dxMesh)); IUnknownReleaser<ID3DXMesh> meshReleaser(d3dxMesh); // Copy in vertex data BYTE* verts = NULL; BYTE* srcVerts = reinterpret_cast<BYTE*>(sdkMesh.GetRawVerticesAt(vbIndex)); UINT vbStride = sdkMesh.GetVertexStride(meshIdx, 0); UINT declStride = D3DXGetDeclVertexSize(vbElements, 0); DXCall(d3dxMesh->LockVertexBuffer(0, reinterpret_cast<void**>(&verts))); for (UINT vertIdx = 0; vertIdx < numVerts; ++vertIdx) { memcpy(verts, srcVerts, declStride); verts += declStride; srcVerts += vbStride; } DXCall(d3dxMesh->UnlockVertexBuffer()); // Copy in index data void* indices = NULL; void* srcIndices = sdkMesh.GetRawIndicesAt(ibIndex); DXCall(d3dxMesh->LockIndexBuffer(0, &indices)); memcpy(indices, srcIndices, numPrims * 3 * indexSize); DXCall(d3dxMesh->UnlockIndexBuffer()); // Set up the attribute table DWORD* attributeBuffer = NULL; DXCall(d3dxMesh->LockAttributeBuffer(0, &attributeBuffer)); UINT numSubsets = sdkMesh.GetNumSubsets(meshIdx); D3DXATTRIBUTERANGE* attributes = new D3DXATTRIBUTERANGE[numSubsets]; ArrayDeleter<D3DXATTRIBUTERANGE> attributeDeleter(attributes); for (UINT i = 0; i < numSubsets; ++i) { SDKMESH_SUBSET* subset = sdkMesh.GetSubset(meshIdx, i); attributes[i].AttribId = subset->MaterialID; attributes[i].FaceStart = static_cast<DWORD>(subset->IndexStart / 3); attributes[i].FaceCount = static_cast<DWORD>(subset->IndexCount / 3); attributes[i].VertexStart = static_cast<DWORD>(subset->VertexStart); // attributes[i].VertexCount = static_cast<DWORD>(subset->VertexCount); attributes[i].VertexCount = numVerts; for (UINT faceIdx = attributes[i].FaceStart; faceIdx < attributes[i].FaceStart + attributes[i].FaceCount; ++faceIdx) attributeBuffer[faceIdx] = subset->MaterialID; } DXCall(d3dxMesh->UnlockAttributeBuffer()); d3dxMesh->SetAttributeTable(attributes, numSubsets); // Generate initial adjacency vector<DWORD> initialAdjacency; initialAdjacency.resize(d3dxMesh->GetNumFaces() * 3); DXCall(d3dxMesh->GenerateAdjacency(0.0001f, &initialAdjacency[0])); // Make the mesh Mesh mesh; mesh.CreateFromD3DXMesh(directory, device, d3d9Device, d3dxMesh, false, false, &initialAdjacency[0], indexType); meshes.push_back(mesh); } }