OpenGL изначально написан на языке C, и активно используется в приложениях на этом языке и родственном ему C++. Однако, этим инструментом можно пользоваться в языке Rust, не теряя производительности, но приобретая дополнительные проверки безопасности. Ниже я рассмотрю один из способов делать это.
Для начала, следует сделать локальный крейт-библиотеку с биндингами для gl, добавив в build-dependencies крейт gl_generator. В нём необходимо настроить генерацию биндингов и билд-скрипте и создать структуру-обёртку для контекста gl.
В основной программе необходимо создать обёртки для текстур, шейдеров и программ, содержащих информацию о gl-контексте и id для работы с данными. Это необязательный шаг, можно работать с голыми данными из gl, как это обычно делают в C. Однако написание обёртки позволит в значительной степени инкапсулировать unsafe-код.
Для загрузки текстур можно использовать крейт image, позволяющий загрузить изображение из файла, а затем преобразовать его к потоку байтов в необходимом формате и загрузить его в видеопамять с использованием функций gl.TexImage2D и gl.BindTexture.
Также понадобятся абстракции для работы с vbo: структуры, которые будут передаваться с шейдером, помеченные атрибутом #[repr(C, packed)], который указывает компилятору, что структура должна размещаться в памяти, в соответствие со стандартом языка C, структуры для моделей, инкапсулирующие собственную загрузку в vbo.
Полезно также использовать крейт cgmath, так как он предоставляет большое количество функций для работы с матрицами, например матрицы смещения и поворота, а также матрицы преобразования для камеры.
Чтобы создать окно, к которому затем будет подключен gl, воспользуемся крейтом sdl2, являющимся обёрткой для одноимённой библиотеки.
Создадим экземпляр окна:
let video_subsystem = sdl.video().expect(“Could not get sdl video subsystem”);
let window = video_subsystem
.window(title, width, height)
.opengl()
.resizable()
.build()
.expect(“Could not create window”);
Затем получим экземпляр контекста gl:
let gl = gl::Gl::load_with(|s| {
video_subsystem.gl_get_proc_address(s) as *const std::os::raw::c_void
});
Установим размеры видимого окна, очистим его каким-нибудь цветом и включим проверку глубины, для работы алгоритма z-buffer:
unsafe {
gl.Viewport(0, 0, width as gl::types::GLint, height as gl::types::GLint);
gl.ClearColor(red, green, blue, alpha);
gl.Enable(gl::DEPTH_TEST);
}
Затем в цикле будем отрисовывать все необходимые модели, используя шейдеры и текстуры.
sdl позволяет получить обработчик событий клавиатуры и мыши. Из которого на каждой итерации цикла можно доставать все события и обрабатывать их. Таким образом можно даже написать простую игру. Для этого также будет полезно выключить отображение курсора и включить относительные координаты смещения мыши.