Урок Инициализация в Windows я начинаю это пособие непосредственного с кода, разбитого на секции, каждая из которых будет подробно комментироваться. Первое, что вы должны сделать это создать проект в Visual C++



страница26/27
Дата17.11.2018
Размер7.85 Mb.
ТипУрок
1   ...   19   20   21   22   23   24   25   26   27
ARB_MULTISAMPLE позволяет нам это сделать. По существу, каждый пиксель представлен своими соседями для определения оптимального сглаживания. Как бы то ни было этот процесс дорого обходится и может замедлить производительность. Например, требуется больше видеопамяти:

 

Vid_mem = sizeof(Front_buffer) +

          sizeof(Back_buffer) +

          num_samples * (sizeof(Front_buffer) +sizeof(Z_buffer))

 

Более подробную информацию относительно сглаживания, также как о том, что я собираюсь рассказать, можно найти по этим адресам:



 

GDC2002 -- OpenGL Multisample (http://developer.nvidia.com/attach/3464)

OpenGL Pixel Formats and Multisample Antialiasing (http://developer.nvidia.com/attach/2064)

Антиалиасинг сегодня (http://www.nvworld.ru/docs/fsaa2.html)

 

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



 

Наш процесс выглядит следующим образом:

·         Создается обычное окно

·         Собираем возможные значения форматов пикселей для последующего сглаживания (InitMultisample)

·         Если сглаживание возможно, то уничтожаем окно и создаем его заново, с новым форматом пикселя.

·         Для частей, которые мы хотим сгладить, просто вызываем функциюglEnable(GL_ARB_MULTISAMPLE).

 

Начнем с начала и поговорим о нашем исходном файле – arbMultiSample.cpp. Начинаем со стандартного включения заголовочных файлов gl.h и glu.h, а также windows.h. О arb_multisample.h мы поговорим позже.



 

#include

#include

#include

#include "arb_multisample.h"

 

Две строчки ниже определяют точки входа в список строк WGL. Мы будем их использовать при доступе к атрибутам формата пикселя для определения формата нашего типа. Две другие переменные нужны для доступа к нашим данным.



 

// Объявления, которые мы будем использовать

#define WGL_SAMPLE_BUFFERS_ARB  0x2041

#define WGL_SAMPLES_ARB         0x2042

 

bool arbMultisampleSupported = false;



int  arbMultisampleFormat = 0;

 

Следующей функцией, о которой мы поговорим, является WGLisExtensionSupported, которая будет использована для сбора информации о WGL расширениях для определения поддерживаемого формата на нашей системе. Мы будем давать описания кода по мере продвижения по нему, так как это легче чем прыгать по странице туда сюда.



 

Примечание: Код внизу написан Генри Гоффином. Его изменения внесли: Улучшенный разбор расширений GL и решили проблему с выпаданием кода, если первая проверка была не успешной.

 

bool WGLisExtensionSupported(const char *extension)



{

  const size_t extlen = strlen(extension);

  const char *supported = NULL;

 

  // попытка использовать wglGetExtensionStringARB на текущем контексте, если возможно



  PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");

 

  if (wglGetExtString)



    supported = ((char*(__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC());

 

  // Если  проверка не пройдена, то попытаемся использовать стандартное расширение OpenGL



  if (supported == NULL)

    supported = (char*)glGetString(GL_EXTENSIONS);

 

  // Если и это не поддерживается, тогда работаем без расширений



  if (supported == NULL)

    return false;

 

  // Начинаем проверку с начала строки, увеличиваем на 1, при false совпадение



  for (const char* p = supported; ; p++)

  {


    // Продвигаем p до следующего возможного совпадения

    p = strstr(p, extension);

 

    if (p == NULL)



      return false; // Совпадения нет

 

    //Убедимся, что есть совпадение в начале строки,



    //или первый символ – пробел, или может быть случайное

    //совпадение "wglFunkywglExtension" с "wglExtension"

 

    // Также убедимся, что текущий символ пустой или пробел



    // или еще "wglExtensionTwo" может совпасть с "wglExtension"

    if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))

      return true; // Совпадение

  }


}

 

Примечание переводчика:

Работа с wglGetProcAddress описана в уроке 22. Функция const char *wglGetExtensionsStringARB(HDC hdc) возвращает строку с перечнем расширений, hdc – контекст устройства.

 

Следующая функция – собственно суть всей программы. В сущности, мы собираемся выяснить поддерживается ли наше arb расширение на нашей системе. По сему мы будем запрашивать контекст устройства с целью выяснить наличие метода множественной выборки. Опять… давайте просто перейдем к коду.



 

bool InitMultisample(HINSTANCE hInstance,HWND hWnd,PIXELFORMATDESCRIPTOR pfd)

  // посмотрим, есть ли строка в WGL!



  if (!WGLisExtensionSupported("WGL_ARB_multisample "))

  {


    arbMultisampleSupported=false;

    return false;

  }

 

  // Возьмем наш формат пикселя



  PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB =

    (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");

 

  if (!wglChoosePixelFormatARB)



  {

    // Мы не нашли поддержки для метода множественной выборки, выставим наш флаг и выйдем.

    arbMultisampleSupported=false;

    return false;

  }

 

  // Получаем контекст нашего устройства. Нам это необходимо для того, что



  // спросить у OpenGL окна, какие атрибуты у нас есть

  HDC hDC = GetDC(hWnd);

 

  int pixelFormat;



  bool valid;

  UINT numFormats;

  float fAttributes[] = {0,0};

 

  // Эти атрибуты – биты, которые мы хотим протестировать в нашем типе



  // Все довольно стандартно, только одно на чем мы хотим

  // действительно сфокусироваться - это SAMPLE BUFFERS ARB и WGL SAMPLES

  // Они выполнят главную проверку на предмет: есть или нет

  // у нас поддержка множественной выборки

  int iAttributes[] = {

    WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, // Истинна, если формат пикселя может быть использован в окне

    WGL_SUPPORT_OPENGL_ARB,GL_TRUE, // Истинна, если поддерживается OpenGL

    WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, // Полная аппаратная поддержка

    WGL_COLOR_BITS_ARB,24,          // Цветность

    WGL_ALPHA_BITS_ARB,8,           // Размерность альфа-канала

    WGL_DEPTH_BITS_ARB,16,          // Глубина буфера глубины

    WGL_STENCIL_BITS_ARB,0,         // Глубина буфера шаблона

    WGL_DOUBLE_BUFFER_ARB,GL_TRUE,  // Истина, если используется двойная буферизация

    WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, // Что мы и хотим

    WGL_SAMPLES_ARB, 4 ,            // проверка на 4x тип

    0,0};

 

  // Сначала посмотрим, сможем ли мы получить формат пикселя для 4x типа



  valid = wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixelFormat,&numFormats);

 

  // Если вернулось True, и наш счетчик форматов больше 1



  if (valid && numFormats >= 1)

  {


    arbMultisampleSupported  = true;

    arbMultisampleFormat  = pixelFormat; 

    return arbMultisampleSupported;

  }


 

  // Формат пикселя с 4x выборкой отсутствует, проверяем на 2x тип

  iAttributes[19] = 2;

  valid = wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixelFormat,&numFormats);

  if (valid && numFormats >= 1)

  {


    arbMultisampleSupported  = true;

    arbMultisampleFormat  = pixelFormat;

    return arbMultisampleSupported;

  }


   

  // возвращаем годный формат

  return  arbMultisampleSupported;

}

 



Примечание переводчика:

Функция:


 

BOOL wglChoosePixelFormatARB(HDC hdc,

                             const GLint *piAttribIList,

                             const GLfloat *pfAttribFList,

                             GLuint nMaxFormats,

                             GLint *piFormats,

                             GLuint *nNumFormats);

 

Выбирает форматы пикселя согласно запрашиваемым атрибутам. hdc – контекст устройства, piAttribIList или pfAttribFList – список желаемых атрибутов (пары {тип, значение} формате целого числа или в формате с плавающей запятой, в конце списка {0,0}, значения типов атрибутов задаются объявлениями define выше или взяты из wglext.h, значение зависит от типа). nMaxFormats – максимальное число форматов, которое будет возвращено. piFormats – массив индексов форматов пикселов, которые совпадают с запрашиваемым. Наилучший формат будет первым. nNumFormats – сколько форматов найдено при запросе.



 

Теперь, когда у нас есть готовый код запроса, мы должны изменить процесс создания окна. Сперва, мы должны включить наш заголовочный файл arb_multisample.h и поместить прототипы DestroyWindow и CreateWindow в начало файла.

 

#include       // Заголовочный файл библиотеки Windows



#include         // Заголовочный файл  библиотеки OpenGL32

#include        // Заголовочный файл библиотеки GLu32

#include "NeHeGL.h"       // Заголовочный файл NeHeGL основного кода

 

// ЗДЕСЬ ПРОБЕЖАЛ ТАРАКАН



#include "ARB_MULTISAMPLE.h"

 

BOOL DestroyWindowGL (GL_Window* window);



BOOL CreateWindowGL (GL_Window* window);

// ENDТАРАКАН

 

Следующий кусок кода должен быть добавлен в функцию CreateWindowGL, код функции был оставлен без изменений, дабы вы могли вносить свои модификации. В общем, мы делаем часть «уничтожения» до конца работы. Мы не можем запросить формат пикселя, для определения типа множественной выборки, пока мы не создадим окно. Но мы не можем создать окно, пока не знаем формат пикселя, который оно поддерживает. Сродни вечному вопросу о курице и яйце. Итак, все, что я сделал – это маленькая двухпроходная система; мы создаем окно, определяем формат пикселя, затем уничтожаем (пересоздаем) окно, если метод множественной выборки поддерживается. Немного круто…



 

  window->hDC = GetDC (window->hWnd); // Забираем контекст данного окна

  if (window->hDC == 0)               // Мы получили контекст устройства?

  {


    // Нет

    DestroyWindow (window->hWnd);     // Уничтожаем окно

    window->hWnd = 0;                 // Обнуляем указатель

    return FALSE;                     // возвращаем False

  }

 

// ЗДЕСЬ ПРОБЕЖАЛ ТАРАКАН



  // Наш первый проход, множественная выборка пока не подключена, так что мы создаем обычное окно

  // Если поддержка есть, тогда мы идем на второй проход

  // это значит, что мы хотим использовать наш формат пикселя для выборки

  // и так, установим PixelFormat в arbMultiSampleformat вместо текущего

  if(!arbMultisampleSupported)

  {


    PixelFormat = ChoosePixelFormat (window->hDC, &pfd); // найдем совместимый формат пикселя

    if (PixelFormat == 0)             // мы нашли его?

    {

      // Нет



      ReleaseDC (window->hWnd, window->hDC);  // Освобождаем контекст устройства

      window->hDC = 0;                // Обнуляем контекст

      DestroyWindow (window->hWnd);   // Уничтожаем окно

      window->hWnd = 0;               // Обнуляем указатель окна

      return FALSE;                   // возвращаем False

    }


  }

  else


  {

    PixelFormat = arbMultisampleFormat;

  }

// ENDТАРАКАН



 

  // пытаемся установить формат пикселя

  if (SetPixelFormat (window->hDC, PixelFormat, &pfd) == FALSE)

  {


    // Неудача

    ReleaseDC (window->hWnd, window->hDC); // Освобождаем контекст устройства

    window->hDC = 0;                  // Обнуляем контекст

    DestroyWindow (window->hWnd);     // Уничтожаем окно

    window->hWnd = 0;                 // Обнуляем указатель окна

    return FALSE;                     // возвращаем False

  }

 

Теперь окно создано и у нас есть правильный указатель, чтобы запросить поддержку множественной выборки. Если поддержка есть, то мы уничтожаем окно и опять вызываем CreateWindowGL с новым форматом пикселя.



 

  // Сделаем контекст визуализации нашим текущим контекстом

  if (wglMakeCurrent (window->hDC, window->hRC) == FALSE)

  {


    // Не удалось

    wglDeleteContext (window->hRC);   // Уничтожаем контекст визуализации

    window->hRC = 0;                  // Обнуляем контекст визуализации

    ReleaseDC (window->hWnd, window->hDC); // Освобождаем контекст устройства

    window->hDC = 0;                  // Обнуляем его

    DestroyWindow (window->hWnd);     // Уничтожаем окно

    window->hWnd = 0;                 // Обнуляем указатель окна

    return FALSE;                     // возвращаем False

  }

 

 



// ЗДЕСЬ ПРОБЕЖАЛ ТАРАКАН

  // Теперь, когда наше окно создано, мы хотим узнать какие типы доступны.

  // Мы вызываем нашу функцию InitMultiSample для создания окна

  // если вернулся правильный контекст, то мы уничтожаем текущее окно

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

  if(!arbMultisampleSupported && CHECK_FOR_MULTISAMPLE)

  {

    if(InitMultisample(window->init.application->hInstance,window->hWnd,pfd))



    {

      DestroyWindowGL (window);

      return CreateWindowGL(window);

    }


  }

// ENDТАРАКАН

 

  ShowWindow (window->hWnd, SW_NORMAL);  // Сделаем окно видимым



  window->isVisible = TRUE;

 

Ок, и так настройка теперь завершена! Мы настроили наше окно для работы с методом множественной выборки. Теперь повеселимся, собственно делая это! К счастью, ARB решила сделать поддержку метода множественной выборки динамической, это позволяет нам включать и выключать ее вызовами glEnable / glDisable.



 

glEnable(GL_MULTISAMPLE_ARB);

 

// Визуализируем сцену



 

glDisable(GL_MULTISAMPLE_ARB);

 

Вот собственно и все! Далее идет код примера, в котором простые квадраты вращаются, чтобы вы могли увидеть, как хорошо метод множественной выборки работает. НАСЛАЖДАЙТЕСЬ!



Урок X1. Улучшенная обработка ввода с использованием DirectInput и Windows

Вы должны использовать самые современные технологии, чтобы конкурировать с такими играми как Quake и Unreal. В этом уроке я научу вас, как подключить и использовать DirectInput и как использовать мышь в OpenGL под Windows. Код этого урока базируется на коде урока 10. Начнем.

 

Мышь


 

Первое, что нам понадобиться, это переменная для хранения X и Y позиции мыши.

 

typedef struct tagSECTOR



{

  int numtriangles;

  TRIANGLE* triangle;

} SECTOR;

 

SECTOR sector1;            // Наша модель



 

POINT mpos;                // Позиция мыши (Новое)

 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);  // Объявление WndProc



 

Отлично, как вы видите, мы добавили новую переменную mpos. Структура POINT состоит из двух переменных – x и y, мы будем использовать их для того, чтобы вычислить вращение сцены. Далее мы изменим, часть функции CreateGLWindow() так, как показано ниже.

 

ShowCursor(FALSE);             // Убрать указатель мыши (Изменено)



if (fullscreen)                // Если полноэкранный режим?

{

  dwExStyle=WS_EX_APPWINDOW;  



  dwStyle=WS_POPUP;

}

 



Выше мы переместили вызов ShowCursor(FALSE) так, чтобы курсора мыши не было видно не только в полноэкранном режиме, но и в оконном тоже. Теперь нам нужно получить и установить координаты мыши каждый кадр, поэтому измените функцию WinMain() так как показано ниже:

 

SwapBuffers(hDC);              // Смена буферов (двойная буферизация)



GetCursorPos(&mpos);           // Получить текущую позицию мыши (Новое)

SetCursorPos(320,240);         // Установить мышь в центр окна (Новое)

heading += (float)(320 - mpos.x)/100 * 5;//Обновить направление движения (Новое)

yrot = heading;                // Обновить вращение вокруг оси Y (Новое)

lookupdown -= (float)(240 - mpos.y)/100 * 5;//Обновить вращение вокруг X (Новое)

 

Сначала мы получили позицию мыши при помощи функции GetCursorPos(POINT p). Смещение от центра окна даст нам информацию о том, куда и насколько нужно вращать камеру. Затем мы устанавливаем мышь в центр окна для следующего прохода используя SetCursorPos(int X, int Y).



 

Замечание: Не устанавливайте позицию мыши в 0,0! Если вы сделаете это, то не сможете обработать перемещение мыши вверх и влево, потому что 0,0 это левый верхний угол окна. 320, 240 – это центр окна для режима 640х480.

 

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



 

float = (P - CX) / U * S;

 

P – точка, в которую мы устанавливаем мышь каждый кадр



CX – текущая позиция мыши

U – единицы

S – скорость мыши (будучи истинным квакером я люблю в этом месте значение 12).

 

По этой формуле вычисляются значения переменных heading и lookupdown.



 

С мышью вроде как разобрались. Идем дальше.

 

Клавиатура (DirectX 7)



 

Теперь мы можем при помощи мыши вращать камеру в нашем мире. Следующий шаг использовать клавиатуру для перемещения вперед, атаки и приседания. Довольно болтовни, начнем кодировать.

 

Сначала я расскажу, как использовать DirectX7. Первый шаг – настройка компилятора. Я покажу, как сделать это на примере Visual C++, настройка других компиляторов может отличаться от предложенного способа.



 

Если у вас еще нет DirectX SDK, то вам придется его заиметь, например, скачать с сайта MicroSoft, и проинсталлировать его.

 

После этого, в VisualStudio зайдите в меню Project->Settings. Выберите закладку Link и в строке Object/libraty modules в начало строки добавьте dinput.lib dxguid.lib winmm.lib. Библиотеки DirectInput, DirectX GUID и Windows Multimediaсоответственно, последняя необходима для таймера. Возможно, вам также понадобиться войти в меню Tools->Options и на закладке Directories добавить пути (Include files и Library files) к DirectX SDK и переместить их наверх списка.



 

Теперь DirectInput готов к использованию, можно начинать программировать!

 

Мы нуждаемся в подключении заголовочных файлов DirectInput, для того чтобы мы могли использовать некоторые его функции. Также мы нуждаемся в создании и добавлении новых переменных для DirectInput и для устройства DirectInput клавиатуры. Сделаем мы это следующим образом:



 

#include              // Заголовочный файл стандартного ввода/вывода

#include              // Заголовочный файл библиотеки OpenGL32

#include             // Заголовочный файл библиотеки GLu32

#include           // Заголовочный файл библиотеки Glaux

#include             // DirectInput функции  (Новое)

 

LPDIRECTINPUT7       g_DI;     // DirectInput (Новое)



LPDIRECTINPUTDEVICE7 g_KDIDev; // Устройство клавиатуры (Новое)

 

 



В последних две строчках объявляются  переменные для DirectInput (g_DI) и для устройства клавиатуры (g_KDIDev), последнее будет получать данные и обрабатывать их. Константы DirectInput не сильно отличаются от стандартных констант Windows.

 

Windows       DirectInput



VK_LEFT        DIK_LEFT

VK_RIGHT      DIK_RIGHT

... и так далее

 

Основное отличие в замене VK на DIK. Хотя некоторые названия изменили существенно. Все DIK константы объявлены в файле dinput.h.



 

Теперь нужно написать функцию инициализации DirectInput’а и устройства клавиатуры. Под CreateGLWindow() добавьте следующее:

 

 

// Инициализация DirectInput (Новое)



int DI_Init()

{

  // Создание DirectInput



  if ( DirectInputCreateEx( hInstance,    // Instance окна

        DIRECTINPUT_VERSION,              // Версия DirectInput

        IID_IDirectInput7,

        (void**)&g_DI,                    // DirectInput

        NULL ) )                          // NULL параметр

  {


    return(false);                        // Не создался DirectInput

  }


 

  // Создание устройства клавиатуры

  if ( g_DI->CreateDeviceEx(  GUID_SysKeyboard, 

               // Какое устройство создается (клавиатура, мышь или джойстик)

        IID_IDirectInputDevice7, 

        (void**)&g_KDIDev,       // Устройство клавиатуры

        NULL ) )                 // NULL параметр

  {


    return(false);               // Не создалось устройство клавиатуры

  }


 

  // Установка формата данных для клавиатуры

  if ( g_KDIDev->SetDataFormat(&c_dfDIKeyboard) )

  {


    return(false);            // Не удалось установить формат данных

    // здесь не хватает функций уничтожения устройства клавиатуры и DirectInput

  }

 

  // Установка уровня кооперации



  if ( g_KDIDev->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE) )

  {


    return(false);            // Не удалось установить режим

    // здесь не хватает функций уничтожения устройства клавиатуры и DirectInput

  }

 

  if (g_KDIDev)              // Создано устройство клавиатуры? (лишняя проверка)



    g_KDIDev->Acquire();     // Взять его под контроль

  else                       // если нет

    return(false);           // возвращаем false

 

  return(true);              // все отлично



}

 

// Уничтожение DirectInput



void DX_End()

{

  if (g_DI)



  {

    if (g_KDIDev)

    {

      g_KDIDev->Unacquire();



      g_KDIDev->Release();

      g_KDIDev = NULL;

    }

 

    g_DI->Release();



    g_DI = NULL;

  }


}

 

Этот код в достаточной мере снабжен комментариями и должен быть понятен. Первое – мы инициализируем DirectInput и при помощи него создаем устройство клавиатуры, которое затем берем под контроль. Можно также использовать DirectInput для мыши, но на данном этапе средств Windows вполне достаточно.



 

Теперь нужно заменить старый код обработки ввода с клавиатуры на новый, использующий DirectInput. Изменить предстоит много, приступим.

 

Удалите следующий код из WndProc():

 

  case WM_KEYDOWN:          // Клавиша была нажата?


Каталог: forum
forum -> Лечение гепатозов
forum -> Система ведения овцеводства в крестьянско-фермерских и личных хозяйствах населения
forum -> Yaesuft-857 (ft-897) – переходник для подключения cat интерфейса к микрофонному разъему трансивера
forum -> Васильев Владимир Юрьевич
forum -> tl-wr1043ND Беспроводной гигабитный маршрутизатор серии n copyright & trademarks
forum -> Цели и задачи Контакта rtf docx
forum -> Назовите не менее трех результатов революции 1905- 1907гг. Приведите не менее трех положений, отражающих значение революции для отечественной истории начала 20 века


Поделитесь с Вашими друзьями:
1   ...   19   20   21   22   23   24   25   26   27


База данных защищена авторским правом ©vossta.ru 2019
обратиться к администрации

    Главная страница