Урок 6. Использование OpenGL в SDL

Помечено: , , ,

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 1 год назад.

  • Автор
    Сообщения
  • #3154
    Урок 5 Содержание Урок 7

    На этот раз мы немного отвлечемся от 2D в сторону модного нынче 3D. Не нужно говорить, что на сегодняшний день единственным API для трехмерной графики под Linux является OpenGL. Думаю вы уже знакомы с этой библиотекой, хотя бы немного. Если же нет, то предлагаю сначала почитать основы работы с этой библиотекой (благо в интернете множество документации для начинающих). Данный урок – не самый лучше источник для знакомства с OpenGL. Разработчики SDL – люди неординарного ума. Поэтому неудивительно, что они выбрали гениальную позицию: не создавать свой 3D API, а использовать отточенный годами интерфейс OpenGL. Но не просто использовать, а создали замечательные средства для интеграции OpenGL в SDL приложение. Таким образом мы получаем в распоряжение множество дополнительных средств (таймеры, загрузка изображений, потоки, звук, сеть и т.п.). В прошлом уроке мы разобрали, что расширение DGA2 добавляет аппаратное ускорение к 2D программам. Но на некоторых системах было замечено, что это расширение не работает из-под обычного пользователя. Один из выходов – не использовать средства блиттинга SDL, а использовать OpenGL для отображения 2D. В принципе не сложно переписать например нашу библиотеку для спрайтов с поддержкой OpenGL, т.к. у многих пользователей стоят драйверы, обеспечивающие аппаратное ускорение 3D. Можно дать выбор при компиляции проекта: использовать OpenGL или же средства SDL.

    lesson6

    Создание OpenGL контекста средствами библиотеки SDL в действительности почти не отличается от инициализации обычного приложения SDL. Во-первых, вы должны указать флаг SDL_OPENGL для функции SDL_SetVideoMode(), Во-вторых, необходимо задать несколько параметров для OpenGL приложения (например размеры буфера глубины и буфера кадров) используя специальную функцию SDL_GL_SetAttribute, и наконец, если необходимо использовать двойной буфер, то необходимо установить его при помощи специального GL атрибута, но не нужно указывать флаг SDL_DOUBLEBUF функции SDL_SetVideoMode(), как для 2D приложения, поскольку он не будет работать для контекста OpenGL.

    Для начала необходимо включить нужные файлы заголовков:

    #include "SDL.h" 
    #include "gl.h" 
    #include "glu.h" 

    Пути к этим файлам могут различаться в разных системах, поэтому может потребоваться изменить пути в Makefile (опция I). С самого начала необходимо инициализировать подсистемы:

     if ( SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO) < 0 ){ 
       printf("Unable to init SDL: %s\n", SDL_GetError()); 
       exit(1); 
     } 
     
     atexit(SDL_Quit); 

    В нашем случае это видео подсистема и подсистема таймера для расчета FPS. Также не забываем вызывать функцию SDL_Quit() при выходе из программы.Далее устанавливаем GL атрибуты программы:

     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);

    Функция SDL_GL_SetAttribute в качестве параметров принимает название атрибута и его значение. В нашем случае мы указали использовать двойной буфер (1 – использовать, 0 – не использовать) и указали размеры составляющих каждого цвета для буфера кадров. На самом деле атрибутов несколько больше:

    • SDL_GL_RED_SIZE Размер красной составляющей буфера кадров, бит
    • SDL_GL_GREEN_SIZE Размер зеленой составляющей буфера кадров, бит
    • SDL_GL_BLUE_SIZE Размер синей составляющей буфера кадров, бит
    • SDL_GL_ALPHA_SIZE Размер альфа (прозрачности) составляющей буфера кадров, бит
    • SDL_GL_DOUBLEBUFFER 0 или 1, использовать или не использовать двойной буфер
    • SDL_GL_BUFFER_SIZE Размер буфера кадров, бит
    • SDL_GL_DEPTH_SIZE Размер буфера глубины, бит
    • SDL_GL_STENCIL_SIZE Размер буфера шаблона, бит
    • SDL_GL_ACCUM_RED_SIZE Размер красной составляющей буфера аккумулятора, бит
    • SDL_GL_ACCUM_GREEN_SIZE Размер зеленой составляющей буфера аккумулятора, бит
    • SDL_GL_ACCUM_BLUE_SIZE Размер синей составляющей буфера аккумулятора, бит
    • SDL_GL_ACCUM_ALPHA_SIZE Размер альфа составляющей буфера аккумулятора, бит

    Обратите внимание, что при необходимости использования двойного буфера просто укажите GL атрибут SDL_GL_DOUBLEBUFFER. Установка флага SDL_DOUBLEBUF не оказывает влияния на OpenGL контекст.
    Чтобы атрибуты начали действовать, далее необходимо установить видеорежим и задать флаг SDL_OPENGL:

     if ( SDL_SetVideoMode(640,480,32,SDL_OPENGL) == NULL ){ 
       printf("Unable to set 640x480 video: %s\n", SDL_GetError()); 
       exit(1); 
     }

    Здесь мы создаем окно 640х480 с глубиной цвета 32 бита. Можете установить флаг SDL_FULLSCREEN для работы в полноэкранном режиме.
    На этом инициализация OpenGL контекста закончена! Далее устанавливаем необходимые режимы стандартными функциями GL и GLU, такие как например цвет очищения экрана и тип проекции. В главном цикле программы мы обрабатываем нажатие клавиш и рисуем сцену. Обратите внимание, что для обновления экрана при использовании двойного буфера (в большинстве своем программы его используют) необходимо использовать специальную функцию SDL_GL_SwapBufers() вместо стандартной функции GL. Это очень важно!

     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     glClearDepth(1.0);
     glDepthFunc(GL_LESS);
     glEnable(GL_DEPTH_TEST);
     glShadeModel(GL_SMOOTH);
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluPerspective(45.0f,640/480,0.1f,100.0f);
     glMatrixMode(GL_MODELVIEW);   
     
     SDL_TimerID my_timer_id = SDL_AddTimer(1000, my_callbackfunc, my_callback_param);

    Устанавливаем режимы OpenGL и инициализируем таймер.

     int done=0; 
     while(done == 0){ 
       SDL_Event event; 
       
       while ( SDL_PollEvent(&event) ){ 
         if ( event.type == SDL_QUIT ){ 
          done = 1; 
         } 
         if ( event.type == SDL_KEYDOWN ){
           if ( event.key.keysym.sym == SDLK_ESCAPE ){ 
             done = 1; 
           } 
         } 
       } 
       
       DrawGLScene();
       glFlush();
       SDL_GL_SwapBuffers();
       fps++;
     }

    В главном цикле обрабатываем события и рисуем сцену. Обратите внимание на SDL_GL_SwapBuffers()! Функция glFlush() – посылает сцену на конвейер.

    Функция рисования сцены DrawGLScene() на самом деле не представляет никакой сложности. В ней рисуется куб с разноцветными гранями. Глобальные переменные xrf, yrf и zrf – так называемые rotate factors, т.е. угол поворота по соответствующим осям. Каждый фрейм мы изменяем эти значения, создавая интересный эффект вращения куба.

    Еще раз напоминаю, что данный урок не описывает методы рисования средствами OpenGL, а только лишь объясняет способ инициализации трехмерного приложения средствами SDL. Как всегда предлагаю загрузить исходники к уроку и внимательно в них разобраться.

    Урок 5 Содержание

Для ответа в этой теме необходимо авторизоваться.