Библиотека трехмерной графики Open gl


Форма сообщений об ошибках



бет2/15
Дата29.05.2016
өлшемі1.07 Mb.
#100718
1   2   3   4   5   6   7   8   9   ...   15

Форма сообщений об ошибках


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

Добавьте к проекту gl3D новую форму. Для этого



  1. В окне Solution Explorer получите контекстное меню на строке gl3D.

  2. Командой Add->Windows Form откройте окно Add New Item.

  3. В строке Name поставьте имя файла новой формы ErrorMsgForm.cs и нажмите OK

  4. Измените имя вновь созданной формы на ErrorMsgForm в окне Properties новой формы

  5. В том же окне установите свойство формы StartPosition в CenterScreen

  6. Из окна Tools перенесите на форму объект класса RichBoxText

  7. Назовите этот объект errMsgTextBox

  8. В окне Properties установите его свойство Modifiers в public

  9. Там же установите его свойство Dock в Fill

Теперь проведите редакцию файла проекта pr3D.cs:

  1. Добавьте строку using System.IO в самое начало файла

  2. Вместо строки Application.Run поместите следующий код

try

{

Application.Run(new f3D());



}

catch (Exception e)

{

if

(



MessageBox.Show

(

e.Message + "\nДетали?",



Path.GetFileName(Application.ExecutablePath) + " Ошибка!!",

MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation,

MessageBoxDefaultButton.Button1

) == DialogResult.Yes

)

{

// Если запрошены детали,



// создается окно с редактором errMsgTextBox, в который выводится

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

gl3D.ErrorMsgForm emf = new gl3D.ErrorMsgForm();

// В errMsgTextBox помещается строка с подробным сообщением об ошибке

emf.errMsgTextBox.Text = e.ToString();

// Окно изображается в модальном режиме

// (пока окно не закроется, фокус не переводится на другие окна)

emf.ShowDialog();

// Окно уничтожается в памяти

emf.Dispose();

}

Application.Exit();



}

Для описания ошибок времени выполнения будет использоваться механизм объектов исключительной ситуации. Этот механизм предполагает, что при возникновении ошибки в операторах, находящихся в блоке try (в данном случае практически в любом месте выполняемой программы, т.к. в блоке try находится основной метод Application.Run с формой f3D), управление передается в блок catch, описанный здесь. Параметром блока catch служит объект "e" класса исключительной ситуации Exception, порожденный ошибочным кодом, или намеренно созданный программистом. У объектов класса Exception есть свойство Message, содержащее краткую информацию об ошибке. Метод ToString() объектов класса Exception возвращает полное описание маршрута к источнику ошибки. Проверка работы этого механизма будет проведена ниже на конкретном примере.

Скомпилируйте новую версию проекта.

Первые команды

Комплексная цель модуля



  • Познакомиться с тем, как создается контекст воспроизведения, необходимый для вывода результатов работы команд OpenGL в окно (на панель).

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

Класс контекста воспроизведения


В этом разделе

  • Описан класс, позволяющий сопоставить окну (в данном случае панели формы f3D) контекст воспроизведения команд OpenGL. Выполнение методов этого класса является необходимым условием получения изображения.

  • В конструкторе формы f3D создается экземпляр класса контекста воспроизведения, сопоставляемый панели. Этим завершается подготовка окна (панели) к воспроизведению команд OpenGL.

Для использования команд библиотеки OpenGL следует сопоставить панели panelGL формы f3D так называемый контекст воспроизведения. Контекст воспроизведения является портом, через который команды OpenGL будут выводить результат своей работы в окно (в данном случае на панель panelGL). С этой целью



  1. В окне Solution Explorer в раздел References библиотеки GL командой Add References… через контекстное меню добавьте ссылку на библиотеку System.Windows.Forms из вкладки .NET

  2. В начале созданного Вами библиотечного файла GL.cs добавьте операторы ссылок на две библиотеки, т.е. две строки

using System.Runtime.InteropServices;

using System.Windows.Forms;



  1. Уберите скелет класса GL (имя класса с фигурными скобками), предложенный средой по умолчанию

  2. Добавьте код нового класса glPort следующего содержания

///

/// Управляет созданием и освобождением контекста воспроизведения OpenGL

///

public class glPort : IDisposable

{

///



/// Буфер дублирован.

///

const uint PFD_DOUBLEBUFFER = 0x00000001;

///

/// Буфер может передавать содержание в окно или на поверхность устройства

///

const uint PFD_DRAW_TO_WINDOW = 0x00000004;

///

/// Буфер поддерживает команды OpenGL.

///

const uint PFD_SUPPORT_OPENGL = 0x00000020;

///

/// Описывает формат пикселей изображающей поверхности.

///

[StructLayout(LayoutKind.Sequential)]

class PIXELFORMATDESCRIPTOR

{

internal short nSize = 40;



internal short nVersion = 1;

internal uint dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |PFD_DOUBLEBUFFER;

internal byte iPixelType;

internal byte cColorBits = 32;

internal byte cRedBits;

internal byte cRedShift;

internal byte cGreenBits;

internal byte cGreenShift;

internal byte cBlueBits;

internal byte cBlueShift;

internal byte cAlphaBits = 8;

internal byte cAlphaShift;

internal byte cAccumBits = 8;

internal byte cAccumRedBits;

internal byte cAccumGreenBits;

internal byte cAccumBlueBits;

internal byte cAccumAlphaBits;

internal byte cDepthBits = 32;

internal byte cStencilBits = 8;

internal byte cAuxBuffers;

internal byte iLayerType;

internal byte bReserved;

internal int dwLayerMask;

internal uint dwVisibleMask;

internal uint dwDamageMask;

}

#region Поля и свойства



///

/// Хранит идентификатор библиотечного модуля OpenGL

///

static int openGLdllHandle;

///

/// Хранит дескриптор формата пикселей

///

PIXELFORMATDESCRIPTOR pixelFD = new PIXELFORMATDESCRIPTOR();

///

/// Устанавливает и возвращает текущий контекст устройства

///

public int deviceContext

{

private set;



get;

}

///



/// Хранит текущий контекст воспроизведения

///

int renderContext;

///

/// Хранит идентификатор (хэндл) окна

///

int controlHandle;

#endregion

#region Статические методы

#region Методы установки формата пикселей

///

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

/// наиболее близким к данному формату.

///

///

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

///

///

/// Ссылка на экземпляр структуры типа PIXELFORMATDESCRIPTOR,

/// который определяет требуемый формат пикселя

///

///

/// Индекс искомого формата пикселей. Если функция выполнена успешно,

/// то это значение больше нуля.

/// Если нет, то значение равно нулю.

///

[DllImport("GDI32")]

static extern int ChoosePixelFormat(int dvcContext,

[MarshalAs(UnmanagedType.LPStruct)]PIXELFORMATDESCRIPTOR pfd);

///

/// устанавливает формат пикселя указанного контекста устройства в формат,

/// определенный индексом pixelFormatIndex

///

///

/// Контекст устройства, для которого устанавливается данный формат пикселя

///

///

/// Индекс формата пикселя

///

///

/// Ссылка на структуру

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

/// PIXELFORMATDESCRIPTOR, которая содержит спецификацию формата пикселя.

///

///

/// При успешном завершении возвращает TRUE, в противном случае FALSE.

///

[DllImport("GDI32")]

static extern bool SetPixelFormat(int dvcContext, int pixelFormatIndex,

[MarshalAs(UnmanagedType.LPStruct)]PIXELFORMATDESCRIPTOR pfd);

#endregion

#region Методы манипуляции с контекстами

///

/// Возвращает идентификатор контекста устройства дисплея для клиентской области окна.

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

/// создающих изображение на клиентской области окна.

///

///

/// идентификатор (хэндл) окна, чей контекст должен быть возвращен

///

///

/// При успешном завершении возвращает идентификатор контекста устройства,

/// в противном случае 0

///

[DllImport("User32")]

static extern int GetDC(int handle);

///

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

///

///

/// идентификатор (хэндл) окна, чей контекст должен быть освобожден

///

///

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

///

///

/// При успешном завершении возвращает 1, в противном случае 0

///

[DllImport("User32")]

static extern int ReleaseDC(int handle, int dvcContext);

///

/// Создает новый контекст воспроизведения OpenGL.

/// Контекст воспроизведения соответствует устройству с заданным контекстом.

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

///

///

/// Идентификатор контекста устройства

///

///

/// При успешном завершении возвращает идентификатор контекста воспроизведения,

/// в противном случае 0

///

[DllImport("OPENGL32.DLL")]

static extern int wglCreateContext(int dvcContext);

///

/// Уничтожает контекст воспроизведения

///

///

/// Идентификатор контекста воспроизведения

///

///

/// При успешном завершении возвращает TRUE, в противном случае FALSE.

///

[DllImport("OPENGL32.DLL")]

static extern bool wglDeleteContext(int rndContext);

///

/// Производит обмен содержимого переднего и заднего буферов,

/// если формат пикселя указанного

/// контекста устройства включает задний буфер (двойная буферизация)

///

///

/// Идентификатор контекста устройства

///

///

/// При успешном завершении возвращает TRUE, в противном случае FALSE.

///

[DllImport("GDI32")]

static extern bool SwapBuffers(int dvcContext);

///

/// Делает указанный контекст воспроизведения OpenGL текущим контекстом

/// для данного подпроцесса (нити).

/// Все последующие вызовы команд OpenGL, сделанные в этом подпроцессе,

/// будут выполняться на устройстве

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

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

///

///

/// Идентификатор контекста устройства

///

///

/// Идентификатор контекста воспроизведения. Если это значение 0,

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

/// В этом случае второй параметр игнорируется.

///

///

/// При успешном завершении возвращает TRUE, в противном случае FALSE.

///

[DllImport("OPENGL32.DLL")]

static extern bool wglMakeCurrent(int dvcContext, int rndContext);

#endregion

///

/// Вводит исполняемый модуль в адресное пространство вызываемого процесса

///

///

/// Имя исполняемого модуля

///

///

/// При успешном завершении возвращает идентификатор (хэндл) загруженного модуля,

/// в противном случае 0

///

[DllImport("Kernel32")]

public static extern int LoadLibrary(String funcname);

#endregion

///

/// Вызывает метод wglMakeCurrent для данных контекстов устройства и воспроизведения

///

///

/// Результат, возвращаемый методом wglMakeCurrent

///

public bool MakeCurrent()

{

return wglMakeCurrent(deviceContext, renderContext);



}

///

/// Вызывает метод SwapBuffers для данного контекста устройства

///

///

/// Возвращает результат метода SwapBuffers

///

public bool SwapBuffers()

{

return SwapBuffers(deviceContext);



}

///

/// Определяет идентификатор данного окна, создает контекст устройства,

/// контекст воспроизведения и делает контекст воспроизведения текущим.

///

///

/// данное окно

///

public glPort(Control control)

{

// Получение контекста устройства



if (0 == (deviceContext = GetDC(controlHandle = (int)control.Handle)))

throw new Exception("Контекст устройства для данного окна не определен.");

// загрузка библиотеки OpenGL

if (openGLdllHandle == 0)

if (0 == (openGLdllHandle = LoadLibrary("OpenGL32.DLL")))

throw new Exception("Библиотека OPENGL32 не включена в процесс.");

// получение индекса требуемого формата пикселя

int pixelFormatIndex = ChoosePixelFormat(deviceContext, pixelFD);

if (0 == pixelFormatIndex)

throw new Exception("Формат пикселей не определен.");

// установка формата пикселя для данного контекста устройства

if (!SetPixelFormat(deviceContext, pixelFormatIndex, pixelFD))

throw new Exception("Формат пикселей не установлен.");

// создание контекста воспроизведения OpenGL для данного контекста устройства

if (0 == (renderContext = wglCreateContext(deviceContext)))

throw new Exception("Контекст воспроизведения не установлен.");

// контекст воспроизведения делается текущим

if (!wglMakeCurrent(deviceContext, renderContext))

throw new Exception("Контекст не установлен текущим.");

}

///



/// Уничтожает контекст воспроизведения и освобождает контекст устройства текущего окна

///

public void Dispose()

{

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



if (!wglMakeCurrent(0, 0))

throw new Exception("Контекст не установлен нулем.");

if (renderContext > 0)

// уничтожается контекст воспроизведения

if (!wglDeleteContext(renderContext))

throw new Exception("Контекст воспроизведения не освобожден.");

if (deviceContext > 0)

// освобождается контекст устройства

if (0 == ReleaseDC(controlHandle, deviceContext))

throw new Exception("Контекст устройства не освобожден.");

renderContext = deviceContext = 0;

}

}



Перенесите этот код и ознакомьтесь с комментариями. Скомпилируйте решение.

К ссылкам проекта gl3D добавьте ссылку на библиотеку GL (контекстное меню над пунктом References проекта gl3D, команда Add references…, вкладка Projects).

Для использования класса glPort с панелью panelGL перейдите к редактированию файла главной формы проекта f3D.cs.


  1. В заголовке файла добавьте ссылку на библиотеку GL командой using GL;

  2. В тело класса f3D добавьте раздел "Рабочие поля и свойства" с описанием поля port

#region Рабочие поля и свойства

///

/// Хранит текущий порт воспроизведения команд OpenGL

///

glPort port;

#endregion



  1. В тело конструктора формы (метод f3D) после операторов установки размеров формы добавьте оператор создания объекта port = new glPort(panelGL); Этот оператор должен создать контекст воспроизведения команд OpenGL на панели panelGL сразу же после создания формы и основных инициализирующих действий.

  2. Выберите окно дизайнера и в окне Properties для формы f3D назначьте обработчик событию FormClosed (вкладка с изображением молнии содержит обработчики событий), дважды щелкнув по полю справа.

  3. Среда откроет тело обработчика этого события с именем f3D_FormClosed. Добавьте в него код освобождения контекстов port.Dispose(); Этот код освободит контексты после закрытия формы. Обработчик поместите в отдельный раздел (region), назвав этот раздел «Обработчики формы»

  4. В тело класса формы f3D добавьте раздел "Методы воспроизведения" с описанием метода RenderFrame

#region Методы воспроизведения

///

/// Устанавливает воспроизводимую сцену и копирует буферы

///

void RenderFrame()

{

if (!port.SwapBuffers())



throw new Exception("Не выполнен обмен буферов.");

}

#endregion



  1. В окне Properties найдите объект panelGL и добавьте обработчик события Paint.

  2. В тело обработчика добавьте оператор вызова созданного метода RenderFrame();

Этот вызов перенесет содержимое заднего буфера панели PanelGL в передний буфер, передав тем самым изображение на экран.

Обработчик panelGL_Paint поместите в раздел "Обработчики panelGL" так, что результат редакции будет выглядеть следующим образом

#region Обработчики panelGL

private void panelGL_Paint(object sender, PaintEventArgs e)

{

RenderFrame();



}

#endregion

Активируйте проект. Если все сделано верно, должны увидеть черную панель.

Пройдите по коду проекта шагами с помощью команды отладчика Step Into из меню Debug. Эта процедура позволит увидеть последовательность выполнения операторов проекта.

Чтобы понять, как работает механизм реакции на ошибки в созданном коде, в библиотеке GL закройте комментаторскими скобками /* … */ строки загрузки библиотеки OpenGL в теле конструктора glPort. Это строки

if (openGLdllHandle == 0)

if (0 == (openGLdllHandle = LoadLibrary("OpenGL32.DLL")))

throw new Exception("Библиотека OPENGL32 не включена в процесс.");

Активируйте проект. Результатом должно быть появление окна сообщения об ошибке типа "Контекст воспроизведения не установлен".

Вновь пройдите по шагам код проекта командой Step Into.

Уберите комментаторские скобки и вернитесь к работающей версии проекта.
Тест рубежного контроля


  1. Что описывает класс PIXELFORMATDESCRIPTOR?

  2. Что делает метод SetPixelFormat?

  3. Каковы параметры метода MakeCurrent?

  4. Что делает метод CreateContext?

  5. Что возвращает метод ChoosePixelFormat?

  6. Как используется метод SwapBuffers?

  7. Как сопоставить контексты воспроизведения двум различным панелям?

  8. Укажите верную последовательность использования методов, перечисленных в вопросах 2-5.

  9. Почему необходимо вызывать метод RenderFrame в обработчике перерисовки панели?

  10. Опишите последовательность выполнения методов в форме f3D на протяжении всего жизненного цикла формы.





Достарыңызбен бөлісу:
1   2   3   4   5   6   7   8   9   ...   15




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет