Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Листинг 7.9. Эффекты экрана (SCREENFX.C).






// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ////////////////////////////////////////

#include < io.h>

#include < conio.h>

#include < stdio.h>

#include < stdlib.h>

#include < dos.h>

#include < bios.h>

#include < fcntl.h>

#include < memory.h>

#include < malloc.h>

#include < math.h>

#include < string.h>

#include " graph0.h" // включаем нашу графическую библиотеку

// СТРУКТУРА.///////////////////////////////////////////////

typedef struct worm_typ

{

int у; // текущая Y-координата " червячка"

int color; // цвет " червячка"

int speed; // скорость " червячка"

int counter; // счетчик

}, worm, *worm_ptr;

// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ///////////////////////////////////

unsigned int far *clock = (unsigned int far *)0x0000046C;

// указатель на внутренний таймер 18.2 " тик" /с

pcx_picture screen_fx; // наш тестовый экран

worm worms[320]; // используется при оплывании экрана

//ФУНКЦИИ /////////////////////////////////////////////////

 

void Timer(int clicks)

{

// эта функция использует внутренний таймер с частотой 18.2 " тик" /с

// 32-битовое значение этого таймера имеет адрес 0000: 046Ch

unsigned int now;

// получим текущее время

now = *clock;

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

// Заметьте, что каждый " тик" имеет длительность примерно в 55 мс

while(abs(*clock - now) < clicks){}

} // конец Timer ////////////////////////////////////////////////////////////

void Fade_Lights (void)

{ // эта функция гасит свет, медленно уменьшая значения цветов

// во всех цветовых регистрах

int index, pal_reg;

RGB_color color, color_1, color_2, color_3;

for (index=0; index< 30; index++)

{

for (pal_reg=l; pal_reg< 255; pal_reg++)

{

// получить затемняемый цвет

Get_Palette_Register(pal_reg, (RGB_color_ptr)& color);

if (color.red > 5) color.red-=3;

else

color.red = 0;

if (color.green > 5) color.green-=3;

else

color.green = 0;

if (color.blue > 5) color.blue-=3;

else

color.blue = 0;

// уменьшить интенсивность цвета

Set_Palette_Register(pal_reg, (RGB_color_ptr)& color);

} // конец внутреннего цикла

// немного подождем

Timer(2);

} // конец внешнего цикла } // конец Fade_Lights

///////////////////////////////////////////////////////////

void Disolve(void)

{

// " растворение" экрана рисованием биллиона черных пикселей

unsigned long index;

for (index=0; index< =300000; index++, Plot_Pixel_Fast(rand()%320, rand()%200, 0));

} // конец Disolve

//////////////////////////////////////////////////////////

void Melt(void)

{

// Функция " оплавляет" экран, двигая маленьких " червячков"

// с разной скоростью вниз по экрану. Эти " червячки" меняют

// на своем пути цвет пикселей.

int index, ticks=0;

// инициализация " червячков"

for (index=0; index< 160; index++)

{

worms[index].color = Get_Pixel(index, 0);

worms[index].speed = 3 + rand()%9;

worms[index].у =0;

worms[index].counter = 0;

// прорисовка " червячка"

Plot Pixel_Fast((index< < 1), 0, (char) worms [index].color);

Plot_Pixel_Fast((index< < 1), 1, (char) worms [index].color);

Plot_Pixel_Fast((index< < 1), 2, (char) worms [index].color);

Plot_Pixel_Fast((index< < 1) + l, 0, (char) worms [index].color);

Plot_Pixel_Fast((index< < 1) + 1, 1, (char) worms [index].color);

Plot_Pixel_Fast((index< < 1) + 1, 2, (char) worms [index].color);

} // конец цикла

// плавим экран

while(++ticks< 1800)

{

// работа " червячков"

for (index=0; index< 320; index++)

{

// пора подвинуть " червячка"

if (++worms[index].counter == worms[index].speed)

{

// обнуляем счетчик

worms[index].counter = 0;

worms[index].color = Get_Pixel(index, worms[index], y+4);

// достиг " червячок" низа экрана?

if (worms[index].у < 193)

{ Plot_Pixel_Fast ((index< < 1), worms [index].y, 0);

Plot Pixel Fast ((index< < 3.), worms [index].y+1,

(char)worms[index].color);

Plot_Pixel_Fast ((index< < 1), worms [index].y+2,

(char)worms[index].color);

Plot Pixel Fast ((index< < 1), worms [index].y+3,

(char)worms[index].color);

Plot Pixel Fast ((index< < 1) +1, worms [index].y, 0);

Plot_Pixel_Fast((index< < 1)+1, worms [index].y+1,

(char)worms[index].color);

Plot Pixel Fast ((index< < 1)+l, worms [index].y+2,

(char)worms[index].color);

Plot_Pixel_Fast ((index< < 1)+1, worms [index].y+3,

(char)worms[index].color);

worms[index].y++;

} // конец оператора if

} // конец оператора if

} // конец цикла // ускоряем плавление

if (! (ticks % 500))

{

for (index=0; index< 160; index++) worms[index].speed--;

} // конец оператора if

} // конец оператора while

} // конец Melt

// ОСНОВНАЯ ПРОГРАММА //////////////////////////////////////

void main(void)

(

int index,

done=0,

sel;

// установка видеорежима 320х200х256

Set_Mode(VGA256);

PCX_lnit((pcx_picture_ptr)& screen_fx);

PCX_Load(" war.pcx", (pcx_picture_ptr)& screen_fx, 1);

PCX_Show_Buffer((pcx_picture_ptr) & screen_fx);

PCX_Delete((pcx_picture_ptr)& screen_fx);

_settextposition(22, 0);

printf('1 - Fade Lights.\n2 - Disolve.\n3 - Meltdown.");

// какой эффект хочет увидеть игрок? switch(getch())

{

case '1': // гаснущий экран {

Fade_Lights();

} break;

case '2': // растворяющийся экран {

Disolve();

} break;

case '3': // оплывающий экран {

Melt(};

} break;

} //конец оператора switch

// возврат в текстовый режим

Set_Mode(TEXT_MODE);

} // конец функции main

Пробовали ли вы текстурировать?

Так как основная тема всех наших разговоров — это то, как сделать трехмерную игру типа DOOM с текстурированными поверхностями, то мне следует рассказать вам о несомненно важной вещи, которую мы еще не обсуждали — об этом самом тексту рировании. Все эти темные комнаты и туннели просто обязаны иметь действительно потрясающую текстуру. Здесь есть только одна проблема, а что если вы не художник-профессионал? Как же вы их сделаете?

Вы будете приятно удивлены, узнав что достаточно внимательно посмотреть на всевозможные здания и сооружения, а затем посвятить некоторое время программе Deluxe Paint. Взгляните на рис. 7.8.

Эти несколько грубых текстур я сделал с помощью этой программы за несколько минут. Эти текстуры не так уж плохи, к тому же они показывают, что это можно сделать и не будучи профессионалом. Однако если вы рисуете совсем как кура лапой, то можете воспользоваться тысячей уже готовых текстур с одного из многочисленных дисков CD-ROM.

(Однако, пожалуйста, не размещайте водопроводные краны и ванные на стенах, как это сделано в некоторых играх, названия которых вы сами легко вспомните.)

Масштабирование растровых изображений

Люди обычно говорят: «А вот это мы оставим на сладкое...». В нашем случае мы оставили на сладкое самое сложное, что есть в этой главе. Я пытался свести всю математическую часть к минимуму, зная «любовь» программистов к тригонометрическим функциям и умножению. К сожалению, трехмерные игры содержат довольно сложные алгоритмы и математику. Масштабирование битовых образов - это именно одна из таких областей.

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

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

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

Если вы посмотрите внимательно, то увидите, что на рисунке 7.10 ровно в два раза больше пикселей, чем на рисунке 7.9.

Удвоение количества пикселей будет работать, если мы хотим увеличить, образ точнс? в два раза. Однако, если же мы захотим увеличить образ на произвольный коэффициент (как мы будем делать позже при создании нашей трехмерной игры), то нам потребуется более общий алгоритм. Я расскажу вам о восхитительно простом способе масштабирования растрового изображения. Он настолько прост, что просто кажется невозможным!

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

Например, если мой исходный образ состоит из строк по 64 пикселя, и я хочу превратить его в образ со строкой по 100 пикселей, то я должен увеличить количество исходных пикселей как 100/64, то есть примерно в 1.5 раза.

Так как мы знаем, что экран представляет собой матрицу целых, то может показаться, что растягивание какого-либо объекта в нецелое количество раз не будет работать. Однако все не так уж и плохо. Мы можем взять часть исходного изображения и затем поместить его на изображение требуемого размера. Затем используя коэффициент обратный коэффициенту масштабирования, определить индекс следующей части масштабируемого изображения и повторить весь процесс сначала. В результате многократного повторения этой процедуры мы и достигнем желаемого результата.

Вернемся к нашему примеру. Мы хотим в результате масштабирования получить 100 пикселей, которые бы выглядели как исходные 64. Как мы уже посчитали, коэффициент масштабирования должен быть 1.5, следовательно, каждый пиксель должен быть скопирован 1.5 раза. Однако мы не можем этого сделать, так как скопировать только половину пикселя при всем желании не удастся. Испробуем наш альтернативный вариант, и сделаем примерно так:

§ Проиндексируем область значений исходного изображения от 0 до 63;

§ Проиндексируем область значений увеличенного объекта также от 0 до 63, но не целыми, а дробными значениями.

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

Вуаля! Образ увеличился так, как надо. Остался единственный вопрос, какова связь между шагом приращения дробного индекса и коэффициентом масштабирования? Ответ не прост, а очень прост:

1/коэффициент масштабирования

 

И все! Конечно, мы должны изменять масштаб и по координате X, и по координате Y, но алгоритм можно использовать один и тот же. Более того, если объект имеет одинаковые размеры по координатам Х и Y (то есть если он имеет размеры МхМ, а не MxN), то расчеты могут быть выполнены еще быстрее.

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

Чтобы показать работу функции масштабирования объектов я написал демонстрационную программу, которая называется SCALE.С. В ней вы можете выбрать одну из четырех текстур и масштабировать ее, используя клавишу левой угловой скобки (или знака «меньше») для уменьшения и клавишу правой угловой скобки (или знака «больше») — для увеличения объекта. Обратите внимание, что масштабирование действительно замедляется при увеличении объекта, но надо помнить, что это только начало, и нам было важнее всего понять, как все это работает. Листинг 7.10 содержит текст программы. Не забудьте при компоновке программы подключить библиотеку GRAPH0.C.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.