После просмотра этого видео я начал думать о том, как я могу реализовать что-то подобное в моем текущем проекте. Я думаю, что было бы слишком сложно сделать большую часть моего кода редактируемой в реальном времени, но я думал, что смогу хотя бы сделать свои шейдеры OpenGL редактируемыми, когда я играю в игру.
Итак, я создал 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 по существу привязан к одному потоку. AFAIK, для этого есть 2 обходных пути:
- Отключите контекст OpenGL в основном потоке пользовательского интерфейса, включите его в другом потоке, сделайте мои вещи, а затем сбросьте его
- Отправьте событие обратно в основной поток пользовательского интерфейса
Я не уверен, как бы реализовать (1), потому что основной поток пронизан вызовами OpenGL ... Я бы не знал, где его включить или отключить.
Итак, у меня остался вариант (2), за исключением того, что я не могу понять, как отправить событие изменения файла обратно в основной поток.
В этой статье говорится:
GLControl предоставляет метод GLControl.BeginInvoke () для упрощения вызовов асинхронных методов из вторичных потоков в основной поток System.Windows.Forms.Application. GameWindow не предоставляет аналогичный API.
К сожалению, я использую GameWindow
, поэтому не знаю, как получить доступ к этой функции.
Итак, какой самый простой способ отправить мое событие обратно в основной поток пользовательского интерфейса? Используете ли вы библиотеку OpenTK или другую предпочтительно библиотеку, не предназначенную только для Windows?