Dmitry Kurtaev/ C++: Multiply GLUT windows

Задача: использование нескольких окон из GLUT с различными функциями рисования.
Пример: с использованием C++, freeglut.
Языки: EN, RU

Главы

Создание простого окна
Создание двух окон
Функционал окна внутри класса
Оконный менеджер
Окно внутри окна
Полезные ссылки

Создание простого окна

GLUT - библиотека, предоставляющая функционал для создания окон, в которых происходит отображение того, что мы нарисовали с помощью OpenGL. Кроме создания, мы можем навесить на них обработчики событий от пользователя: изменение размеров окна, нажатие клавиш, движение мыши. Каждый из обработчиков является функцией, которую принято называть callback.
Минимальный код, демонстрирующий работу библиотеки, включает в себя инициализацию самого GLUT, инициализацию окна (начальные размер и положение), регистрацию требуемых обработчиков событий.

Создающиеся окна имеют рамку, стандартную для имеющейся операционной системы. На изображениях представлен вид окон программы, запускаемой на Ubuntu 16.04LTS.
Single view
Дополнение: GLUT мощный и простой в использовании инструмент для создания окон и работы с пользователем через них. Благодаря именно удобству использования, не стоит требовать от него операций уровня операционной системы. Таких как, например, скрытие заголовка (рамки) созданного окна, поддержание окна поверх остальных окон.

Создание двух окон

Проинициализируем последовательно два окна, каждый из которых свяжем с собственной функцией отрисовки.

Two views

Функционал окна внутри класса

Задача, в том виде как она сформулирована, может считаться решённой. Но что, если нам потребуется иметь большее число окон, с более сложной логикой отрисовки и обработкой событий? Давайте попробуем инкапсулировать работу с окном для будущей масштабируемости приложений, использующих GLUT.
Вернёмся на этап создания одного окна и реализуем класс, обеспечивающий тот же функционал.

С точки зрения пользователя класса, достаточно выбрать заголовок создаваемого окна, не заботясь о внутренней реализации.

Относительно класса, мы просто оборачиваем существующие функции в соответствующие методы. Для регистрации методов как обработчиков событий, необходима статическая реализация.

Оконный менеджер

Необходимо использовать созданный класс для управления несколькими окнами. Из-за того, что функция отрисовки статична, она одинакова для каждого из объектов класса. Для решения проблемы, объявим функцию display абстрактной, что позволит реализовать функционал в классах-наследниках. А в качестве обработки события отрисовки, вызовем перерисовку всех имеющихся окон.

Обратим внимание, что функция display_all будет зарегестрирована на каждое окно. То есть при необходимости перерисовки одного из окон, будут перерисованы все.

Ранее, у нас были различные функции для различных окон и мы не заботились о том, чтобы идентифицировать окно. Сейчас такая задача возникает. Если развернуть цикл вызовов display внутри display_all, от каждой из реализации класса, получится, что актуальной будет лишь последняя итерация (произойдёт очередная очистка методом glClear(..) и обновление содержимого окна методом glutSwapBuffers()). Для разрешения конфликта, используем функцию glutSetWindow(..), которая устанавливает текущее окно, для которого применяются последующие инструкции.

Для создания нового окна, можно объявить класс-наследник с собственной реализацией метода display.

Окно внутри окна

В качестве дополнения, рассмотрим задачу разделения единственного окна на области, в каждой из которых собственные функции отрисовки и прочие callback функции.
GLUT имеет функцию glutCreateSubWindow(..), которая создает окно в пространстве родительского, существующего окна.

Subwindow

Дополнение: дочернее окно будет иметь постоянный размер, не смотря на изменение размеров родительского окна. При необходимости, можно самостоятельно организовать изменение размеров, используя относительные координаты, пробрасывая события от родительских окон дочерним.

Полезные ссылки

OpenGL 2.1 Reference Pages
freeglut API