Прямо сейчас я моделирую какую-то маленькую библиотеку OpenGL, чтобы дурачиться с графическим программированием и т. Д. Поэтому я пока использую классы, чтобы обернуться вокруг определенных вызовов функций OpenGL, таких как создание текстур, создание шейдеров и так далее, пока чтотак хорошо.
Моя проблема:
Все вызовы OpenGL должны выполняться потоком, которому принадлежит созданный контекст OpenGL (по крайней мере, в Windows, любой другой поток будетничего не делать и создать ошибку OpenGL).Итак, чтобы получить контекст OpenGL, я сначала создаю экземпляр класса окна (просто еще одну оболочку для вызовов Win API) и, наконец, создаю контекст OpenGL для этого окна.Это звучало довольно логично для меня.(Если в моем дизайне уже есть недостаток, который заставляет вас кричать, дайте мне знать ...)
Если я хочу создать текстуру или любой другой объект, для создания которого требуются вызовы OpenGL, я делаю это(вызываемый конструктор объекта OpenGL, пример):
opengl_object()
{
//do necessary stuff for object initialisation
//pass object to the OpenGL thread for final contruction
//wait until object is constructed by the OpenGL thread
}
Итак, на словах я создаю объект, как любой другой объект, используя
opengl_object obj;
, который затем в своем конструкторе, помещает себя в очередь объектов OpenGL, создаваемых потоком контекста OpenGL.Затем поток контекста OpenGL вызывает виртуальную функцию, которая реализована во всех объектах OpenGL и содержит необходимые вызовы OpenGL для окончательного создания объекта.
Я действительно думал, что такой способ решения этой проблемы был бы хорош.Тем не менее, прямо сейчас, я думаю, что я ужасно неправ.
Дело в том, что, хотя описанный выше способ работает до сих пор прекрасно, у меня возникают проблемы, как только иерархия классов углубляется.Например (что не совсем идеально, но это показывает мою проблему):
Допустим, у меня есть класс sprite, представляющий, очевидно, Sprite.Он имеет собственную функцию создания для потока OpenGL, в котором вершины и координаты текстуры загружаются в память графических карт и так далее.Это пока не проблема.Скажем так, я хочу иметь 2 способа рендеринга спрайтов.Один экземпляр и один через другой.Итак, я бы закончил с 2 классами, sprite_instanced и sprite_not_instanced.Оба являются производными от класса sprite, так как оба являются sprite, которые отображаются только по-разному.Однако sprite_instanced и sprite_not_instanced нуждаются в дополнительных вызовах OpenGL в своей функции create.
Мое решение до сих пор (и я чувствую себя по-настоящему ужасно!)
У меня есть какое-то понимание того, как работает генерация объектов в c ++ и как это влияет на виртуальные функции,Поэтому я решил использовать виртуальную функцию создания класса sprite только для загрузки данных вершин и т. Д. В графическую память.Затем виртуальный метод создания sprite_instanced выполнит подготовку к визуализации этого спрайта.Итак, если я хочу написать
sprite_instanced s;
Во-первых, вызывается конструктор спрайта, и после некоторой инициализации конструирующий поток передает объект в поток OpenGL.На этом этапе переданный объект является просто обычным спрайтом, поэтому будет вызван sprite :: create, а поток OpenGL создаст нормальный спрайт.После этого конструирующий поток вызовет конструктор sprite_instanced, снова выполнит некоторую инициализацию и передаст объект в поток OpenGL.На этот раз, однако, это sprite_instanced и, следовательно, будет вызываться sprite_instanced :: create.
Так что, если я прав с приведенным выше предположением, все происходит именно так, как должно, по крайней мере, в моем случае.Я провел последний час, читая о вызове виртуальных функций из конструкторов и о том, как строится v-таблица и т. Д. Я провел некоторый тест, чтобы проверить мои предположения, но это может зависеть от компилятора, поэтому я не полагаюсь на них на 100%,Кроме того, это просто ужасно и похоже на ужасный взлом.
Другое решение
Другая возможность - реализовать фабричный метод в классе потоков OpenGL, чтобы позаботиться об этом. Поэтому я могу выполнять все вызовы OpenGL внутри конструктора этих объектов. Однако в этом случае мне понадобится много функций (или один подход на основе шаблонов), и возникает ощущение возможной потери потенциального времени рендеринга, когда поток OpenGL имеет больше возможностей, чем нужно ...
Мой вопрос
Можно ли справиться с этим так, как я описал выше? Или мне лучше выбросить это и заняться чем-нибудь другим?