2012-03-03 21 views
0

this videoを見た後、私は自分の現在のプロジェクトでそれをどうやって実装できるか考え始めました。私は大量のコードをリアルタイムで編集可能にするのは難しいと思っていますが、少なくとも私がゲームをプレイするときにはOpenGLシェーダを編集可能にすることができました。OpenTK GameWindowを使用する場合、メインのUIスレッドにイベントを戻す方法は?

だから私はFileSystemWatcherを設定します。

protected void WatchShaders() 
{ 
    _uiDispatcher = Dispatcher.CurrentDispatcher; 
    const string shaderDir = @"path\to\my\shaders"; 
    _shaderFileWatcher = new FileSystemWatcher(shaderDir); 
    _shaderFileWatcher.NotifyFilter = NotifyFilters.LastWrite; 
    //fw.Filter = "*.frag;*.vert"; 
    _shaderFileWatcher.Changed += ShaderChanged; 
    _shaderFileWatcher.EnableRaisingEvents = true; 
} 

そして今、私はいつでもファイルの変更シェーダを更新する:

void ShaderChanged(object sender, FileSystemEventArgs e) 
{ 
    _shaderFileWatcher.EnableRaisingEvents = false; // prevent more/duplicate events from firing before we've finished processing the current one 

    lock (_bfShader) 
    { 
     _bfShader.AttachShader(Shader.FromFile(e.FullPath)); 
     _bfShader.Link(); 
     _bfShader.Use(); 

     _bfProjUniform = new Uniform(_bfShader, "ProjectionMatrix"); 
     _bfSampler = new Uniform(_bfShader, "TexSampler"); 
     _bfSampler.Set1(0); 
    } 
    _shaderFileWatcher.EnableRaisingEvents = true; 
} 

問題は、できるだけ早く私は私のシェーダファイルを編集するようです

現在呼び出し中のスレッドにコンテキストがありません

だから私は掘り下げて、OpenGLのコンテキストが本質的に単一のスレッドにバインドされていることを知りました。私の知る限り、2つの回避策はこのためにあります

  1. がメインに戻ってイベントを送出し、それをリセットし、その後、他のスレッドでそれを有効にすると、メインUIスレッド上のOpenGLコンテキストを無効にし、私のものを行うと、 UIスレッド

メインスレッドがOpenGL呼び出しで謎に包まれているため、どのように実装するのかよくわかりません...有効にしたり無効にする場所がわかりません。

私は、ファイル変更イベントをメインスレッドに戻す方法を知ることができないことを除いて、オプション(2)が残っています。

This articleは言う:

GLControlメインSystem.Windows.Forms.Applicationスレッドに二次スレッドからの非同期メソッド呼び出しを簡単にするGLControl.BeginInvoke()メソッドを提供します。 GameWindowは同様のAPIを提供していません。

残念ながら私はGameWindowを使用していますので、その機能にアクセスする方法がわかりません。

イベントをメインのUIスレッドに戻すにはどうすれば最も簡単ですか? OpenTKライブラリを使用するか、別の、好ましくは Windows以外のライブラリですか?

答えて

2

考え出した私は、キューを使用することができますし、それをオフ物事を引っ張っ:

void ShaderChanged(object sender, FileSystemEventArgs e) 
{ 
    _shaderFileWatcher.EnableRaisingEvents = false; // prevent more/duplicate events from firing before we've finished processing the current one 

    lock (_renderQueue) 
    { 
     _renderQueue.Enqueue(() => 
      { 
       switch(e.Name) 
       { 
        case "block.frag": 
         _bfShader.DetachShader(_blockFragShader); 
         _blockFragShader = Shader.FromFile(e.FullPath); 
         _bfShader.AttachShader(_blockFragShader); 
         break; 
        default: 
         return; 
       } 

       Trace.TraceInformation("Updating shader '{0}'", e.Name); 

       _bfShader.Link(); 
       _bfShader.Use(); 

       _bfProjUniform = new Uniform(_bfShader, "ProjectionMatrix"); 
       _bfSampler = new Uniform(_bfShader, "TexSampler"); 
       _bfSampler.Set1(0); 
      }); 
    } 

    _shaderFileWatcher.EnableRaisingEvents = true; 
} 

をそして私は少し私のレンダリングループを変更します。

lock(_renderQueue) 
{ 
    while(_renderQueue.Count > 0) 
    { 
     _renderQueue.Dequeue().Invoke(); 
    } 
} 
+1

これは、多くの場合、最善のアプローチです。 'GLControl.BeginInvoke'のようなUIコールバックは、ウィンドウメッセージキューを介して送出され、単純なアプリケーションキューよりもかなり高いオーバヘッドを持ちます。 –

関連する問題