Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2633

.pdf
Скачиваний:
6
Добавлен:
07.01.2021
Размер:
54.26 Mб
Скачать

Рис. 21. Вывод текста на экран с использованием эффекта пульсации растрового шрифта

Измените содержание текста. Измените цвет текста.

Измените время мерцания (счетчик).

Контрольные вопросы

1.Почему размер шрифта задается отрицательным числом?

2.Что будет содержать переменная base после создания списка,

сиспользованием glGenLists?

3.Скакой целью и как задается цветовая пульсация?

4.С какой целью вызывается функция glLoadIdentity()?

5.Что описывает идентификатор набора символов?

2.14. Построение векторных шрифтов

Текст следующего примера так же основывается на коде первого проекта:

#include <windows.h> // Заголовочный файл для Windows

#include <math.h>

// Заголовочный файл для математической

бибилиотеки Windows(добавлено)

#include <stdio.h>

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

ввода/вывода(добавлено)

 

#include <stdarg.h>

// Заголовочный файл для манипуляций

с переменными аргументами (добавлено)

#include <gl\gl.h>

// Заголовочный файл для библиотеки

OpenGL32

 

 

123

#include <gl\glu.h>

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

#include <gl\glaux.h>

// Заголовочный файл для библиотеки GLaux

HDC hDC=NULL;

 

// Частный контекст устройства GDI

HGLRC hRC=NULL;

// Контекст текущей визуализации

HWND hWnd=NULL;

// Декриптор окна

HINSTANCE hInstance;

// Копия приложения

Далее введем две

новые

переменные: переменная base будет

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

GLuint base;

// База отображаемого списка для набора

символов (добавлено)

 

 

GLfloat rot;

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

(добавлено)

 

 

bool keys[256];

// Массив для манипуляций с клавиатурой

bool active=TRUE;

 

// Флаг активности окна, по

умолчанию=TRUE

 

 

bool fullscreen=TRUE;

// Флаг полноэкранного режима, по

умолчанию=TRUE

 

 

GLYPHMETRICSFLOAT gmf[256] будет содержать информацию о местоположении и ориентации каждого из 256 списков отображения нашего векторного шрифта. Чтобы получить доступ к нужной букве просто определим gmf[num], где num – это номер списка отображения, соответствующий требуемой букве:

GLYPHMETRICSFLOAT gmf[256]; // Массив с информацией о шрифте

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

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

построении растрового шрифта. Переменная HFONT font будет содержать идентификатор шрифта Windows. Далее определим переменную base, создав набор из 256-ти списков отображения, вызвав функцию glGenLists(256). После этого переменная base будет содержать номер первого списка отображения:

GLvoid BuildFont(GLvoid)

// Построение растрового шрифта

{

 

HFONT font;

// Идентификатор шрифта Windows

base=glGenLists(256);

// Массив для 256 букв

Далее необходимо создать сам векторный шрифта и определить его размер:

124

font = CreateFont( -12, // Высота шрифта

Определим ширину знакоместа. Ее значение установлено в ноль, тем самым Windows берет значение по умолчанию:

0, // Ширина знакоместа

Угол отношения (Angle of Escapement) позволяет вращать шрифт. Угол наклона (Orientation Angle) определяет угол, в десятых долях

градуса, между базовой линией символа и осью Х экрана:

0,

//Угол перехода

0,

//Угол направления

Ширина шрифта – важный параметр, который может быть в

пределах от 0 до 1000:

 

FW_BOLD,

//Ширина шрифта

Также можно

 

использовать предопределенные значения:

FW_DONTCARE = 0, FW_NORMAL = 400, FW_BOLD = 700 и

FW_BLACK = 900.

 

 

Параметры Italic, Underline и Strikeout (наклонный, подчеркнутый

и зачеркнутый) могут иметь значения TRUE или FALSE:

FALSE,

 

// Курсив

FALSE,

 

// Подчеркивание

FALSE,

 

// Перечеркивание

Идентификатор набора символов определяется как: ANSI_CHARSET, //Идентификатор кодировки

Точность вывода – также важный параметр, который означает, какой тип символа использовать, если их более одного. Например, значение OUT_TT_PRECIS означает, что надо взять TRUETYPE –

версию

шрифта.

Можно

также

использовать

значение

OUT_TT_ONLY_PRECIS, которое означает, что всегда следует брать,

если возможно, шрифт TRUETYPE:

 

 

 

OUT_TT_PRECIS,

// Точность вывода

 

Точность отсечения – этот параметр указывает вид отсечения

шрифта при попадании букв вне определенной области:

 

 

CLIP_DEFAULT_PRECIS,

//Точность отсечения

Качество вывода – параметр, который имеет следующие варианты: ROOF, DRAFT, NONANTIALIASED, DEFAULT или ANTIALIASED.

Сглаживание (Antialiasing) шрифта – это эффект, позволяющий сгладить шрифт в Windows. Он делает вид букв менее ступенчатым:

ANTIALIASED_QUALITY,

// Качество вывода

Следующими идут значения семейства (Family) и шага (Pitch).

Шаг может принимать значения DEFAULT_PITCH, FIXED_PITCH и

VARIABLE_PITCH. Семейство может

быть FF_DECORATIVE,

FF_MODERN, FF_ROMAN, FF_SCRIPT, FF_SWISS, FF_DONTCARE.

Здесь оба параметра установлены по умолчанию:

125

FF_DONTCARE|DEFAULT_PITCH, / Семейство и Шаг Имя используемого шрифта:

"Comic Sans MS"); // Имя шрифта

Далее осуществим выбор шрифта и свяжем его с контекстом устройста (DC):

SelectObject(hDC, font); //Выбрать созданный шрифт

Далее построим векторный шрифт командой wglUseFontOutlines – выбор контекста устройства (DC), начальный символ, количество создаваемых символов, и базовое значение списка отображения:

wglUseFontOutlines( hDC, // Выбрать текущий контекст устройства (DC)

0, // Стартовый символ 256, // Количество создаваемых списков отображения

base, // Стартовое значение списка отображения

Уже при значении 0.0f сглаживание будет видимо. После установки отклонения идет определение толщины шрифта (ширины по оси Z). Толщина, равная 0.0f, даст плоские буквы, то есть двумерные. При значении 1.0f уже будет виден некоторый объем.

Параметр WGL_FONT_POLYGONS создает "твердый" шрифт при помощи полигонов. Последний параметр, gmf указывает на буфер адреса для данных списка отображения:

0.0f, //Отклонение от настоящего контура

0.2f,

//Толщина шрифта по оси Z

WGL_FONT_POLYGONS,

//Использовать полигоны, а не линии

gmf),

//Буфер адреса для данных списка отображения

}

 

Следующий

код удаляет 256 списков отображения из памяти,

начиная с первого списка, номер которого записан в base: GLvoid KillFont(GLvoid) // Удаление шрифта

{

 

 

glDeleteLists(base, 256);

// Удаление всех 256 списков

отображения

 

 

}

 

 

Далее текст помещается в символьную строку fmt:

GLvoid glPrint(const char *fmt, ...)

// Функция вывода текста в

OpenGL

{

В первой строке, приведенной ниже, объявляется и инициализируется переменная length:

float length=0; // Переменная для нахождения // физической длины текста

126

char text[256];

// Здесь строка

va_list ap;

//Указатель на переменный список аргументов

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

Далее осущуствляется проверка наличия текста: if(fmt == NULL) // Если нет текста, return;

В следующих трех строках, программа конвертирует любые символы в переданной строке в представляющие их числа:

va_start(ap, fmt);

// Анализ строки на переменные

vsprintf(text, fmt, ap);

// Конвертация символов в реальные коды

va_end(ap);

// Результат сохраняется в text

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

Значение ширины каждого символа получается из выражения gmf[text[loop]].gmfCellIncX. Если loop будет равна 0, то text[loop] – это будет первый символ строки. Соответственно, при loop, равной 1, то text[loop] будет означать второй символ этой же строки. Ширину символа дает gmfCellIncX.

gmfCellIncX – это расстояние, на которое смещается вправо позиция графического вывода после отображения очередного символа для того, чтобы символы не наложились друг на друга. Расстояние и ширина символа – одно и то же значение.

Высоту символа можно узнать при помощи команды gmfCellIncY: for (unsigned int loop=0; loop<(strlen(text));loop++)

//Цикл поиска размера строки

{

length+=gmf[(unsigned char)text[loop]].gmfCellIncX; // Увеличение размера на ширину символа

}

Полученная величина размера строки преобразуется в отрицательную (потому что будет перемещение влево от центра для центровки текста), затем длина делится на два на – перемещение не всего текста влево, а только его половины:

glTranslatef(-length/2,0.0f,0.0f); //Центровка на экране строки

127

Сохранение в стеке значения GL_LIST_BIT для сохранения glListBase от воздействия любых других списков отображения, используемых в программе

Команда glListBase(base) является указателем, где искать для каждого символа соответствующий список отображения:

glPushAttrib(GL_LIST_BIT);

// Сохраняет в стеке значения

битов списка отображения

 

 

glListBase(base);

// Устанавливает базовый символ в 0

Написание текста на экране. glCallLists выводит всю строку текста на экран сразу, создавая многочисленные списки отображения.

Строки, приведенная ниже, делают следующее. Сначала следует указать, где на экране будут находиться списки отображения. strlen(text) находит количество букв, которые посылаются на экран. Значение GL_UNSIGNED_BYTE – байт позволяет хранить целые числа от 0 до 255, восстанавление из стека GL_LIST_BIT – установки OpenGL обратно, как они были перед установкой базовых значений командой glCallLists(base):

// Создает списки отображения текста glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); glPopAttrib(); // Восстанавливает значение Display List Bits

}

В конце функции InitGL добавляются строки:

int InitGL(GLvoid) // Здесь будут все настройки для OpenGL

{

 

 

glShadeModel(GL_SMOOTH);

// Включить плавное

затенение

 

 

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// Черный фон

glClearDepth(1.0f);

// Настройка буфера глубины

glEnable(GL_DEPTH_TEST);

// Разрешить проверку

глубины

 

 

glDepthFunc(GL_LEQUAL);

// Тип проверки глубины

// Действительно правильно вычислена перспектива

glHint(GL_PERSPECTIVE_CORRECTION_HINT,

GL_NICEST);

 

 

glEnable(GL_LIGHT0);

// Включить встроенное

освещение (черновое)

 

 

glEnable(GL_LIGHTING);

// Разрешить освещение

glEnable(GL_COLOR_MATERIAL); // Включить раскраску

материалов ( новая )

 

 

BuildFont();

 

//Построить шрифт

return TRUE;

// Инициализация прошла успешно

}

 

 

128

Управлять векторными шрифтами можно при помощи команды glScalef(x,y,z). Чтобы сделать буквы в два раза выше – glScalef(1.0f,2.0f,1.0f). Значение 2.0f здесь относится к оси Y и означает, что список отображения нужно нарисовать в двойной высоте. Если это значение поставить на место первого аргумента (Х), то буквы будут в два раза шире:

int DrawGLScene(GLvoid) // Вывод на экран

{

// Очистка экрана и буфера глубины glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

// Сброс вида

glTranslatef(0.0f,0.0f,-10.0f);

// Смещение на 10 единиц в экран

Вращение текста осуществляется следующим образом: следующие три строки поворачивают изображение по трем осям:

glRotatef(rot,1.0f,0.0f,0.0f);

// Поворот по оси X

glRotatef(rot*1.5f,0.0f,1.0f,0.0f);

// Поворот по оси Y

glRotatef(rot*1.4f,0.0f,0.0f,1.0f);

// Поворот по оси Z

Возгорание и затухание цветов получается при помощи функций

SIN и COS.

// Цветовая пульсация основанная на вращении glColor3f(1.0f*float(cos(rot/20.0f)),1.0f*float(sin(rot/25.0f)),

1.0f-0.5f*float(cos(rot/17.0f)));

rot делится на разные числа, так что бы каждый цвет не возрастал

стакой же скоростью.

Вкоде, приведенном ниже, печатается "текст", пробел, тире, пробел и число из переменной rot и деленное на 50, чтобы немного его уменьшить. Если число больше 999.99, разряды слева игнорируются:

glPrint("ASOIU" – %3.2f",rot/50);

// Печать текста на экране

Затем увеличивается переменная rot для дальнейшей пульсации

цвета и вращения текста:

 

rot+=0.5f;

// Увеличить переменную вращения

return TRUE;

// Все прошло успешно

}

 

 

Важно добавить строку KillFont() в конец функции KillGLWindow, которая очистит все, что касалось шрифта, прежде чем выйти из

программы:

 

if (!UnregisterClass("OpenGL",hInstance))

// Если класс

незарегистрирован

 

{

 

MessageBox(NULL,"Could Not Unregister Class.",

"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

129

hInstance=NULL;

// Установить копию приложения в

ноль

}

KillFont(); // Уничтожить шрифт Результат работы программы представлен на рис. 21.

Рис. 21. Вывод текта на экран с использованием векторного шрифта

Измените код программы следующим образом: выберите другой тип шрифта, который Вам нравится, далее измените содержание текста.

Контрольные вопросы

1.Для чего используется переменная rot?

2.Каково предназначение команды glEnable(GL_Color_Material)?

3.как в данном примере используется буфер глубины?

4.Какой командой шрифт выводится на экран?

5.В какой части кода содержится информация о шрифте?

6.Для чего служит фукция gmfCellIncX?

7.Для чего нужен параметр Точность вывода и как его задают?

8.Для чего нужен параметр Точность отсечения и как его

задают?

9.Для чего нужен параметр Качество вывода и как его задают?

2.15.Использование текстурированных шрифтов

130

Код данной программы сновывается на коде предыдущего проекта, в котором был создан векторный шрифт и демонстрирует программу для создания текстурированных шрифтов.

Код, как отмечалось ранее, применим только в Windows. Для построения шрифта используются функции wgl Windows.

#include <windows.h> // Заголовочный файл для Windows

#include <stdio.h>

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

библиотеки ввода/вывода

 

#include <gl\gl.h>

// Заголовочный файл для библиотеки

OpenGL32

 

#include <gl\glu.h>

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

#include <gl\glaux.h>

// Заголовочный файл для библиотеки GLaux

#include <math.h>

// Заголовочный файл для математической

библиотеки

 

HDC hDC=NULL;

// Приватный контекст устройства GDI

HGLRC hRC=NULL; // Постоянный контекст рендеринга HWND hWnd=NULL;// Сохраняет дескриптор окна HINSTANCE hInstance; // Сохраняет экземпляр приложения

bool keys[256];

// Массив для работы с клавиатурой

bool active=TRUE;

// Флаг активации окна, по умолчанию =

TRUE

 

bool fullscreen=TRUE;// Флаг полноэкранного режима Необходимо добавить одну новую переменную целого типа,

которая называется texture[], которая будет использоваться для хранения текстуры. Последние три строки не изменяются:

GLuint texture[1];

// Одна текстура

GLuint base;

// База списка отображения для фонта

GLfloat rot;

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

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

Wingdings – специальный шрифт и требует некоторых модификаций, чтобы заставить программу работать с ним. При этом надо не просто сообщить Windows, что будет использоваться wingdingsшрифт. Необходимо сообщить Windows, что шрифт является специальным шрифтом, и не стандартным символьным шрифтом:

GLvoid BuildFont(GLvoid) // Построение шрифта

{

GLYPHMETRICSFLOAT gmf[256]; // Адрес буфера для

хранения шрифта

 

HFONT font;

// ID шрифта в Windows

base = glGenLists(256);

// Храним 256 символов

font = CreateFont( -12,

// Высота фонта

131

0,

// Ширина фонта

0,

// Угол отношения

0,

// Угол наклона

FW_BOLD,

// Ширина шрифта

FALSE,

// Курсив

FALSE,

// Подчеркивание

FALSE,

// Перечеркивание

Вместо того чтобы использовать ANSI_CHARSET, используем SYMBOL_CHARSET, т.е. шрифт, который строится – не обычный шрифт, составленный из букв. Специальный шрифт обычно составлен

из крошечных картинок (символов):

 

 

SYMBOL_CHARSET,

// Модифицировано –

идентификатор набора символов

 

 

Следующие строки не изменились:

 

OUT_TT_PRECIS,

 

// Точность вывода

CLIP_DEFAULT_PRECIS,

 

// Точность отсечения

ANTIALIASED_QUALITY,

/ Качество вывода

FF_DONTCARE|DEFAULT_PITCH, // Семейство и шаг

Теперь, когда выбран идентификатор набора символов, можно

выбирать wingdings шрифт:

 

 

 

"Wingdings");

 

// Имя шрифта ( Модифицировано )

SelectObject(hDC, font);

// Выбрать шрифт, созданный нами

wglUseFontOutlines(hDC,

//Выбрать текущий контекст

устройства (DC)

 

 

 

 

0,

// Стартовый символ

 

256,

// Количество создаваемых списков отображения

base,

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

Следует установить большой уровень отклонения:

0.1f,

// Отклонение от истинного контура

При этом не будет точно отслеживаться контур шрифта. Если задано отклонение равное 0.0f, то могут возникнуть проблемы с текстурированием на очень изогнутых поверхностях. Если допустить некоторое отклонение, большинство проблем исчезнет.

Следующие три строки кода:

0.2f,

// Толщина шрифта по оси Z

WGL_FONT_POLYGONS, // Использовать полигоны, а не линии

gmf);

// Буфер адреса для данных списка

отображения

}

Перед ReSizeGLScene() следует добавить следующий раздел кода для загрузки текстуры. Здесь создается память для хранения растрового

132

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]