#pragma once using namespace System::Collections::Generic; namespace BluntDirectX { namespace Direct3D { public enum class ShaderQuality { Low, Medium, High, }; public ref class Effect { private: static ID3DXEffectPool* effectPool; static Effect() { ID3DXEffectPool* e; D3DXCreateEffectPool( &e ); effectPool = e; } ShaderQuality shaderQuality; internal: ID3DXEffect* effect; public: Effect(GraphicsDevice^ device, Stream^ data) { ID3DXEffect* e; ID3DXBuffer* compilationErrors; HRESULT hr; data->Position = 0; array^ bytes = gcnew array((int)data->Length); data->Read( bytes, 0, (int)data->Length ); pin_ptr pdata = &bytes[0]; if (FAILED( hr = D3DXCreateEffect( device->device, pdata, (UINT)data->Length, NULL, NULL, D3DXSHADER_PACKMATRIX_COLUMNMAJOR | D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, effectPool, &e, &compilationErrors ) )) { String^ errors = gcnew String((char*)compilationErrors->GetBufferPointer()); compilationErrors->Release(); throw gcnew InvalidOperationException( String::Format( "Failed compiling shader; HRESULT={0}, Errors:\n{1}", hr, errors )); } effect = e; Quality = ShaderQuality::High; } IntPtr GetHandle( String^ symbol ) { array^ chars = System::Text::Encoding::ASCII->GetBytes(symbol); pin_ptr p = &chars[0]; IntPtr result = IntPtr((void*)effect->GetParameterByName(NULL, (char*)p)); return result; } ~Effect() { safe_release( effect ); } property ShaderQuality Quality { ShaderQuality get() { return shaderQuality; } void set( ShaderQuality s ) { if (shaderQuality == s) return; shaderQuality = s; switch(s) { case ShaderQuality::High: if (SUCCEEDED(effect->SetTechnique( "high_quality" ))) break; case ShaderQuality::Medium: if (SUCCEEDED(effect->SetTechnique( "med_quality" ))) break; case ShaderQuality::Low: if (SUCCEEDED(effect->SetTechnique( "low_quality" ))) break; default: throw gcnew Exception( "Invalid shader quality" ); } } }; void Commit() { effect->CommitChanges(); } int Begin() { unsigned int passes; effect->Begin( &passes, D3DXFX_DONOTSAVESTATE | D3DXFX_DONOTSAVESHADERSTATE ); return passes; } void End() { effect->End(); } void BeginPass(int pass) { effect->BeginPass( pass ); } void EndPass() { effect->EndPass(); } generic< typename T> where T : value class void SetValue( IntPtr handle, T value ) { pin_ptr pvalue = &value; effect->SetValue( (D3DXHANDLE)handle.ToPointer(), pvalue, sizeof(T) ); } void SetTexture( IntPtr handle, Texture^ texture ) { effect->SetTexture( (D3DXHANDLE)handle.ToPointer(), texture->texture ); } property array>^ ShaderResources { array>^ get() { List>^ resources = gcnew List>(); int id = 0; D3DXHANDLE parameter; while( parameter = effect->GetParameter( NULL, id++ ) ) { D3DXHANDLE annotation; if (!(annotation = effect->GetAnnotationByName( parameter, "src" ))) continue; char* value; HRESULT hr; if (FAILED(hr = effect->GetString( annotation, (LPCSTR*)&value ))) ThrowHelper::Hr(hr); resources->Add( KeyValuePair( IntPtr( (void*)parameter ), gcnew String(value) ) ); } return resources->ToArray(); } } }; }}