// Loads resources void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* model) { this->device = device; blendStates.Initialize(device); rasterizerStates.Initialize(device); depthStencilStates.Initialize(device); samplerStates.Initialize(device); meshVSConstants.Initialize(device); meshPSConstants.Initialize(device); shadowConstants.Initialize(device); evsmConstants.Initialize(device); reductionConstants.Initialize(device); LoadShaders(); D3D11_RASTERIZER_DESC rsDesc = RasterizerStates::NoCullDesc(); rsDesc.DepthClipEnable = false; DXCall(device->CreateRasterizerState(&rsDesc, &noZClipRSState)); D3D11_SAMPLER_DESC sampDesc = SamplerStates::AnisotropicDesc(); sampDesc.MaxAnisotropy = ShadowAnisotropy; DXCall(device->CreateSamplerState(&sampDesc, &evsmSampler)); // Create the staging textures for reading back the reduced depth buffer for(uint32 i = 0; i < ReadbackLatency; ++i) reductionStagingTextures[i].Initialize(device, 1, 1, DXGI_FORMAT_R16G16_UNORM); CreateShadowMaps(); SetModel(model); }
UploadContext ResourceUploadBegin(uint64 size) { Assert_(Device != nullptr); size = AlignTo(size, 512); Assert_(size <= UploadBufferSize); Assert_(size > 0); ClearFinishedUploads(0); while(AllocUploadSubmission(size) == false) ClearFinishedUploads(1); Assert_(UploadSubmissionUsed > 0); const uint64 submissionIdx = (UploadSubmissionStart + (UploadSubmissionUsed - 1)) % MaxUploadSubmissions; UploadSubmission& submission = UploadSubmissions[submissionIdx]; Assert_(submission.Size == size); DXCall(submission.CmdAllocator->Reset()); DXCall(UploadCmdList->Reset(submission.CmdAllocator, nullptr)); UploadContext context; context.CmdList = UploadCmdList; context.Resource = UploadBuffer; context.CPUAddress = UploadBufferCPUAddr + submission.Offset; context.ResourceOffset = submission.Offset; return context; }
void Profiler::StartProfile(const wstring& name) { ProfileData& profileData = profiles[name]; Assert_(profileData.QueryStarted == false); Assert_(profileData.QueryFinished == false); profileData.CPUProfile = false; profileData.Active = true; if(profileData.DisjointQuery[currFrame] == NULL) { // Create the queries D3D11_QUERY_DESC desc; desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; desc.MiscFlags = 0; DXCall(device->CreateQuery(&desc, &profileData.DisjointQuery[currFrame])); desc.Query = D3D11_QUERY_TIMESTAMP; DXCall(device->CreateQuery(&desc, &profileData.TimestampStartQuery[currFrame])); DXCall(device->CreateQuery(&desc, &profileData.TimestampEndQuery[currFrame])); } // Start a disjoint query first context->Begin(profileData.DisjointQuery[currFrame]); // Insert the start timestamp context->End(profileData.TimestampStartQuery[currFrame]); profileData.QueryStarted = true; }
void MeshRenderer::GenAndCacheMeshInputLayout(const Model* model) { // TODO: optimize this; group meshes with the same input layout to reduce api calls for(uint64 i = 0; i < model->Meshes().size(); ++i) { const Mesh& mesh = model->Meshes()[i]; VertexShaderPtr vs = _meshVertexShadersMap[&mesh]; ID3D11InputLayoutPtr inputLayout; if (_meshInputLayouts.find(&mesh) == _meshInputLayouts.end()) { DXCall(_device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), vs->ByteCode->GetBufferPointer(), vs->ByteCode->GetBufferSize(), &inputLayout)); _meshInputLayouts.insert(std::make_pair(&mesh, inputLayout)); } if (_meshDepthInputLayouts.find(&mesh) == _meshDepthInputLayouts.end()) { DXCall(_device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), _meshDepthVS->ByteCode->GetBufferPointer(), _meshDepthVS->ByteCode->GetBufferSize(), &inputLayout)); _meshDepthInputLayouts.insert(std::make_pair(&mesh, inputLayout)); } } }
JBKVertexShader* JBKRender_CreateVertexShader(void* blob, int32_t sizeInBytes, JBKShaderInputElement* elements, uint32_t elementCount) { JBKVertexShader* shader = &g_vertexShaders[g_vertexShaderCount++]; D3D11_INPUT_ELEMENT_DESC inputElementArray[16]; convertInputElements(inputElementArray, elements, elementCount); DXCall(g_device->lpVtbl->CreateVertexShader(g_device, blob, sizeInBytes, NULL, &shader->m_shader)); DXCall(g_device->lpVtbl->CreateInputLayout(g_device, inputElementArray, elementCount, blob, sizeInBytes, &shader->m_inputLayout)); return shader; }
void JBKRender_DrawDebugText(float x, float y, const char* text, uint32_t color) { RECT r; r.left = (LONG)x; r.top = (LONG)y; r.right = r.left; r.bottom = r.top; DXCall( IDirect3DDevice9_BeginScene(gDevice) ); gDebugFont->lpVtbl->DrawTextA(gDebugFont, 0, text, -1, &r, DT_LEFT | DT_TOP | DT_NOCLIP, color); DXCall( IDirect3DDevice9_EndScene(gDevice) ); }
void JBKRender_DrawUserPrimitives(void* data, JBKVertexDataType datatype, JBKPrimitiveType primitivetype, uint32_t primitivecount) { int32_t stride = 0; DWORD fvf = DataTypeToFVF(datatype, &stride); D3DPRIMITIVETYPE d3dprimtype = PrimitiveTypeToD3D(primitivetype); SetupTextureStageStates(fvf); DXCall( IDirect3DDevice9_SetFVF(gDevice, fvf) ); DXCall( IDirect3DDevice9_BeginScene(gDevice) ); DXCall( IDirect3DDevice9_DrawPrimitiveUP(gDevice, d3dprimtype, primitivecount, data, stride) ); DXCall( IDirect3DDevice9_EndScene(gDevice) ); }
ID3DXMesh* Mesh::GenerateNormals(ID3DXMesh* mesh, IDirect3DDevice9* d3d9Device) { // see if we have texture coordinates D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; DXCall(mesh->GetDeclaration(decl)); bool foundTexCoord = false; for (UINT i = 0; i < MAX_FVF_DECL_SIZE; ++i) { if (decl[i].Stream == 0xFF) break; else if(decl[i].Usage == D3DDECLUSAGE_TEXCOORD && decl[i].UsageIndex == 0) { foundTexCoord = true; break; } } // Clone the mesh with a new declaration D3DVERTEXELEMENT9 tcDecl[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; D3DVERTEXELEMENT9 noTCDecl[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() }; D3DVERTEXELEMENT9* newDecl; if (foundTexCoord) newDecl = tcDecl; else newDecl = noTCDecl; ID3DXMesh* clonedMesh = NULL; UINT options = D3DXMESH_MANAGED; if (indexType == Index32Bit) options |= D3DXMESH_32BIT; DXCall(mesh->CloneMesh(options, newDecl, d3d9Device, &clonedMesh)); mesh->Release(); // Generate the normals DXCall(D3DXComputeNormals(clonedMesh, &adjacency[0])); return clonedMesh; }
void SaveTextureAsDDS(ID3D11Resource* texture, const wchar* filePath) { ID3D11DevicePtr device; texture->GetDevice(&device); ID3D11DeviceContextPtr context; device->GetImmediateContext(&context); ScratchImage scratchImage; DXCall(CaptureTexture(device, context, texture, scratchImage)); DXCall(SaveToDDSFile(scratchImage.GetImages(), scratchImage.GetImageCount(), scratchImage.GetMetadata(), DDS_FLAGS_FORCE_DX10_EXT, filePath)); }
TempRenderTarget* PostProcessorBase::GetTempRenderTarget(uint32 width, uint32 height, DXGI_FORMAT format, uint32 msCount, uint32 msQuality, uint32 mipLevels, bool generateMipMaps, bool useAsUAV) { // Look through existing render targets for (size_t i = 0; i < tempRenderTargets.size(); ++i) { TempRenderTarget* rt = tempRenderTargets[i]; if (!rt->InUse && rt->Width == width && rt->Height == height && rt->Format == format && rt->MSCount == msCount && rt->MSQuality == msQuality && (rt->UAView != nullptr) == useAsUAV) { rt->InUse = true; return rt; } } // Didn't find one, have to make one TempRenderTarget* rt = new TempRenderTarget(); D3D11_TEXTURE2D_DESC desc; desc.Width = width; desc.Height = height; desc.ArraySize = 1; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET; if(useAsUAV) desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; desc.CPUAccessFlags = 0; desc.Format = format; desc.MipLevels = mipLevels; desc.MiscFlags = generateMipMaps ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; desc.SampleDesc.Count = msCount; desc.SampleDesc.Quality = msQuality; desc.Usage = D3D11_USAGE_DEFAULT; DXCall(device->CreateTexture2D(&desc, nullptr, &rt->Texture)); DXCall(device->CreateRenderTargetView(rt->Texture, nullptr, &rt->RTView)); DXCall(device->CreateShaderResourceView(rt->Texture, nullptr, &rt->SRView)); if(useAsUAV) device->CreateUnorderedAccessView(rt->Texture, nullptr, &rt->UAView); else rt->UAView = nullptr; rt->Width = width; rt->Height = height; rt->MSCount = msCount; rt->MSQuality = msQuality; rt->Format = format; rt->InUse = true; tempRenderTargets.push_back(rt); return tempRenderTargets[tempRenderTargets.size() - 1]; }
void Effect::ExtractGlobalVars(D3DX11_EFFECT_DESC& effectDesc) { for(U32 i = 0; i < effectDesc.GlobalVariables; ++i) { ID3DX11EffectVariable* pVar = dx11Effect->GetVariableByIndex(i); D3DX11_EFFECT_VARIABLE_DESC varDesc; DXCall(pVar->GetDesc(&varDesc)); ID3DX11EffectType* pType = pVar->GetType(); D3DX11_EFFECT_TYPE_DESC typeDesc; DXCall(pType->GetDesc(&typeDesc)); AddVariable(pVar, &varDesc, &typeDesc); } }
void SwapChain::Reset() { Assert_(swapChain); if(output == nullptr) fullScreen = false; // Release all references for(uint64 i = 0; i < NumBackBuffers; ++i) { DX12::Release(backBuffers[i].Texture.Resource); DX12::RTVDescriptorHeap.FreePersistent(backBuffers[i].RTV); } if(format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) noSRGBFormat = DXGI_FORMAT_R8G8B8A8_UNORM; else if(format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) noSRGBFormat = DXGI_FORMAT_B8G8R8A8_UNORM; else noSRGBFormat = format; if(fullScreen) PrepareFullScreenSettings(); else { refreshRate.Numerator = 60; refreshRate.Denominator = 1; } DXCall(swapChain->SetFullscreenState(fullScreen, NULL)); DXCall(swapChain->ResizeBuffers(NumBackBuffers, width, height, noSRGBFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)); if(fullScreen) { DXGI_MODE_DESC mode; mode.Format = noSRGBFormat; mode.Width = width; mode.Height = height; mode.RefreshRate.Numerator = 0; mode.RefreshRate.Denominator = 0; mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; DXCall(swapChain->ResizeTarget(&mode)); } AfterReset(); }
void SaveTextureAsPNG(ID3D11Resource* texture, const wchar* filePath) { ID3D11DevicePtr device; texture->GetDevice(&device); ID3D11DeviceContextPtr context; device->GetImmediateContext(&context); ScratchImage scratchImage; DXCall(CaptureTexture(device, context, texture, scratchImage)); DXCall(SaveToWICFile(scratchImage.GetImages(), scratchImage.GetImageCount(), WIC_FLAGS_NONE, GetWICCodec(WIC_CODEC_PNG), filePath)); }
ID3DXMesh* Mesh::GenerateTangentFrame(ID3DXMesh* mesh, IDirect3DDevice9* d3d9Device) { // make sure we have a texture coordinate D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; DXCall(mesh->GetDeclaration(decl)); bool foundTexCoord = false; for (UINT i = 0; i < MAX_FVF_DECL_SIZE; ++i) { if (decl[i].Stream == 0xFF) break; else if(decl[i].Usage == D3DDECLUSAGE_TEXCOORD && decl[i].UsageIndex == 0) { foundTexCoord = true; break; } } _ASSERT(foundTexCoord); // Clone the mesh with a new declaration D3DVERTEXELEMENT9 newDecl[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, { 0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 }, { 0, 44, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 }, D3DDECL_END() }; ID3DXMesh* clonedMesh = NULL; UINT options = D3DXMESH_MANAGED; if (indexType == Index32Bit) options |= D3DXMESH_32BIT; DXCall(mesh->CloneMesh(options, newDecl, d3d9Device, &clonedMesh)); mesh->Release(); // Calculate the tangent frame DXCall(D3DXComputeTangentFrameEx(clonedMesh, D3DDECLUSAGE_TEXCOORD, 0, D3DDECLUSAGE_BINORMAL, 0, D3DDECLUSAGE_TANGENT, 0, D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_CALCULATE_NORMALS | D3DXTANGENT_GENERATE_IN_PLACE, &adjacency[0], 0.01f, 0.25f, 0.01f, NULL, NULL)); return clonedMesh; }
void StructuredBuffer::Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 dynamic, bool32 useAsUAV, bool32 appendConsume, bool32 hiddenCounter, const void* initData) { Size = stride * numElements; Stride = stride; NumElements = numElements; Assert_(appendConsume == false || hiddenCounter == false); if(appendConsume || hiddenCounter) useAsUAV = true; D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = stride * numElements; bufferDesc.Usage = useAsUAV ? D3D11_USAGE_DEFAULT : dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_IMMUTABLE; bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; bufferDesc.BindFlags |= useAsUAV ? D3D11_BIND_UNORDERED_ACCESS : 0; bufferDesc.CPUAccessFlags = useAsUAV ? 0 : dynamic ? D3D11_CPU_ACCESS_WRITE : 0; bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; bufferDesc.StructureByteStride = stride; D3D11_SUBRESOURCE_DATA subresourceData; subresourceData.pSysMem = initData; subresourceData.SysMemPitch = 0; subresourceData.SysMemSlicePitch = 0; DXCall(device->CreateBuffer(&bufferDesc, initData != nullptr ? &subresourceData : nullptr, &Buffer)); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.NumElements = numElements; DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); if(useAsUAV) { D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; uavDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.Flags = 0; uavDesc.Buffer.Flags |= appendConsume ? D3D11_BUFFER_UAV_FLAG_APPEND : 0; uavDesc.Buffer.Flags |= hiddenCounter ? D3D11_BUFFER_UAV_FLAG_COUNTER : 0; uavDesc.Buffer.NumElements = numElements; DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); } }
void Effect::SetParam(const string& name, const I32* data, U32 offset, U32 count) { auto it = scalarVars.find(name); _ASSERT(it != scalarVars.end()); ID3DX11EffectScalarVariable* scalarVar = it->second; DXCall(scalarVar->SetIntArray(data, offset, count)); }
void SwapChain::AfterReset() { // Re-create an RTV for each back buffer for(uint64 i = 0; i < NumBackBuffers; i++) { backBuffers[i].RTV = DX12::RTVDescriptorHeap.AllocatePersistent().Handles[0]; DXCall(swapChain->GetBuffer(uint32(i), IID_PPV_ARGS(&backBuffers[i].Texture.Resource))); D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = { }; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtvDesc.Format = format; rtvDesc.Texture2D.MipSlice = 0; rtvDesc.Texture2D.PlaneSlice = 0; DX12::Device->CreateRenderTargetView(backBuffers[i].Texture.Resource, &rtvDesc, backBuffers[i].RTV); backBuffers[i].Texture.Resource->SetName(MakeString(L"Back Buffer %llu", i).c_str()); backBuffers[i].Texture.Width = width; backBuffers[i].Texture.Height = height; backBuffers[i].Texture.ArraySize = 1; backBuffers[i].Texture.Format = format; backBuffers[i].Texture.NumMips = 1; backBuffers[i].MSAASamples = 1; } backBufferIdx = swapChain->GetCurrentBackBufferIndex(); }
void Effect::SetParam(const string& name, const void* data, U32 offset, U32 count) { auto it = structVars.find(name); _ASSERT(it != structVars.end()); ID3DX11EffectVariable* var = it->second; DXCall(var->SetRawValue(data, offset, count)); }
void Effect::SetParam(const string& name, bool data) { auto it = scalarVars.find(name); _ASSERT(it != scalarVars.end()); ID3DX11EffectScalarVariable* scalarVar = it->second; DXCall(scalarVar->SetBool(static_cast<BOOL>(data))); }
void Effect::SetParam(const string& name, const bool* data, U32 offset, U32 count) { auto it = scalarVars.find(name); _ASSERT(it != scalarVars.end()); ID3DX11EffectScalarVariable* pScalarVar = it->second; DXCall(pScalarVar->SetBoolArray((BOOL*)data, offset, count)); }
JBKNativeTextureInfo JBKRender_CreateTextureFromFile(const char* fileName) { JBKNativeTextureInfo result = {0}; IDirect3DTexture9* texture; D3DXIMAGE_INFO info; DXCall( D3DXCreateTextureFromFileEx(gDevice, fileName, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, &info, 0, &texture) ); result.Width = info.Width; result.Height = info.Height; result.Texture = texture; return result; }
void Effect::SetParam(const string& name, I32 data) { auto it = scalarVars.find(name); _ASSERT(it != scalarVars.end()); ID3DX11EffectScalarVariable* scalarVar = it->second; DXCall(scalarVar->SetInt(data)); }
void Effect::SetParam(const string& name, Texture* texture) { auto it = resourceVars.find(name); _ASSERT(it != resourceVars.end()); ID3DX11EffectShaderResourceVariable* srVar = it->second; DXCall(srVar->SetResource(texture->GetSRView())); }
void Effect::SetParam(const string& name, const Matrix* data, U32 offset, U32 count) { auto it = matrixVars.find(name); _ASSERT(it != matrixVars.end()); ID3DX11EffectMatrixVariable* matrixVar = it->second; DXCall(matrixVar->SetMatrixArray((const F32*) data->v, offset, count)); }
void Effect::SetParam(const string& name, const Matrix& data) { auto it = matrixVars.find(name); _ASSERT(it != matrixVars.end()); ID3DX11EffectMatrixVariable* matrixVar = it->second; DXCall(matrixVar->SetMatrix((const F32*) &data)); }
void StagingTexture2D::Initialize(ID3D11Device* device, uint32 width, uint32 height, DXGI_FORMAT format, uint32 numMipLevels, uint32 multiSamples, uint32 msQuality, uint32 arraySize) { D3D11_TEXTURE2D_DESC desc; desc.Width = width; desc.Height = height; desc.ArraySize = arraySize; desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.Format = format; desc.MipLevels = numMipLevels; desc.MiscFlags = 0; desc.SampleDesc.Count = multiSamples; desc.SampleDesc.Quality = msQuality; desc.Usage = D3D11_USAGE_STAGING; DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); Width = width; Height = height; NumMipLevels = numMipLevels; MultiSamples = multiSamples; Format = format; ArraySize = arraySize; };
void* StagingBuffer::Map(ID3D11DeviceContext* context) { D3D11_MAPPED_SUBRESOURCE mapped; DXCall(context->Map(Buffer, 0, D3D11_MAP_READ, 0, &mapped)); return mapped.pData; }
void Effect::SetParam(const string& name, const Vector4f& data) { auto it = vectorVars.find(name); _ASSERT(it != vectorVars.end()); ID3DX11EffectVectorVariable* vectorVar = it->second; DXCall(vectorVar->SetFloatVector((const F32*) &data)); }
void* StagingTexture2D::Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch) { D3D11_MAPPED_SUBRESOURCE mapped; DXCall(context->Map(Texture, subResourceIndex, D3D11_MAP_READ, 0, &mapped)); pitch = mapped.RowPitch; return mapped.pData; }
void Effect::SetParam(const string& name, const Vector4f* data, U32 offset, U32 count) { auto it = vectorVars.find(name); _ASSERT(it != vectorVars.end()); ID3DX11EffectVectorVariable* vectorVar = it->second; DXCall(vectorVar->SetFloatVectorArray((const F32*) data, offset, count)); }