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


Полезное:

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


Категории:

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






Листинг 8.2. Демонстрационная программа новой функции масштабирования (VYREN.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 <graph.h>

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

// ПРОТОТИПЫ ////////////////////////////////////////////////////////

void Create_Scale_Data_X(int scale, int far *row);

void Create_Scale_Data_Y(int scale, int * row);

void Build_Scale_Table(void);

void Scale_Sprite(sprite_ptr sprite,int scale);

void Clear_Double_Buffer(void);

// ОПРЕДЕЛЕНИЯ /////////////////////////////////////////////

#define MAX_SCALE 200 // число звезд на звездном небе

#define SPRITE_X_SIZE 80 // максимальные размеры

#define SPRITE_Y_SIZE 48 // растрового изображения

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

sprite object; // обобщенный спрайт, который

// содержит кадры с космическим

// кораблем

pcx_picture text_cells;// PCX-файл с изображениями

int *scale_table_y[MAX_SCALE+l]; // таблица с предварительно

// рассчитанными коэффициентами

// масштабирования

int far *scale_table_x[MAX_SCALE+l]; // таблица с предварительно

// рассчитанными коэффициентами

// масштабирования

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

void Create_Scale_Data_X(int scale, int far *row)

{

// эта функция масштабирует полосу текстуры для всех возможных

// размеров и создает огромную таблицу соответствий

int х;

float x_scale_index=0, x_scale_step;

// рассчитываем шаг масштабирования или число исходных пикселей

// для отображения на результирующее изображение за цикл

x_scale_step = (float)(sprite_width)/(float)scale;

x_scale_index+=x_scale_step;

for (x=0; x<scale; x++)

{

// помещаем данные в массив для последующего использования

row[x] = (int)(x_scale index+,5);

if (row[x] > (SPRITE_X_SIZE-1)) row[x] = (SPRITE_X_SIZE-1);

// рассчитываем следующий индекс

x_scale index+=x_scale_step;

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

} // конец Create_Scale_Data_X

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

void Create_Scale_Data Y(int scale, int *row)

{

// эта функция масштабирует полосу текстуры для всех возможных

// размеров и создает огромную таблицу соответствий

int у;

float y_scale_index=0, у scale_step;

// рассчитываем шаг масштабирования или число исходных пикселей

// для отображения на результирующее изображение за цикл

у_scale_step = (float)(sprite_height)/(float)scale;

y_scale index+=y_scale_step;

for (y=0; y<scale; y++)

{

// помещаем данные в-массив для последующего использования

row[y] = ((int)(y_scale_index+.5)) * SPRITE_X_SIZE;

if (row[y] > (SPRITE_Y_SIZE-1)*SPRITE_X_SIZE) row[y] = (SPRITE_Y_SIZE-1)*SPRITE_X_SIZE;

// рассчитываем следующий индекс

y_scale_index+==y_scale_step;

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

} // конец Create_Scale_Data_Y //////////////////////////////////////////

void Build_Scale_Table (void)

{ // эта функция строит таблицу масштабирования путем расчета

// коэффициентов масштабирования для всех возможных размеров

// от 1 до 200 пикселей

int scale;

// резервируем память

for (scale=l; scale<=MAX_SCALE; scale++)

{

scale_table_y[scale] = (int *)malloc(scale*sizeof(int)+1);

scale_table_x[scale] = (int far *)_fmalloc(scale*sizeof(int)+l);

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

// создаем таблицу масштабирования для осей X и Y

for (scale=l; scale<=MAX_SCALE; scale++) {

// рассчитываем коэффициент для данного масштаба

Create_Scale_Data_Y(scale, (int *)scale_table_y[scale]);

Create_Scale_Data_X(scale, (int far *)scale_table_x[scale]);

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

}// конец Build_Scale_Table ////////////////////////////////////////////////////////////

void Scale_Sprite(sprite_ptr sprite,int scale)

{

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

char far *work_sprite; // текстура спрайта

int *row_y; // указатель на масштабированные

// по оси Y данные (заметьте, что

// это ближний указатель)

int far *row_x; // указатель на масштабированные

// по оси Х данные (заметьте, что

// это дальний указатель)

unsigned char pixel; // текущий текстель

lnt x, // рабочие переменные

У, column,

work_offset,

video_offset,

video_start;

// если объект слишком мал, то и рисовать его не стоит

if (scale<1) return;

// рассчитываем необходимые для масштабирования данные

row_y = scale_table_y[scale];

row_x = scale table_x[scale];

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

work_sprite = sprite->frames[sprite->curr_frame];

// рассчитываем начальное смещение

video_start = (sprite->y << 8) + (sprite->y << 6) + sprite->x;

// изображение рисуется слева направо и сверху вниз

for (x=0; x<scale; х++)

{

// пересчитываем адрес следующего столбца

video_offset = video_start + х;

// определяем, какой столбец должен быть отображен,

// исходя из индекса масштабирования по оси Х

column = row_x[x];

// Наконец рисуем столбец обычным образом

for (y=0; y<scale; y++)

{

// проверка на "прозрачность"

pixel = work_sprite[work_offset+column];

if (pixel)

double buffer[video_offset] = pixel;

// индекс следующей строки экрана и смещение

//в области хранения текстуры

video_offset += screen_width;

work_offset = row_y[y];

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

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

} // конец Scale_Sprite

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

void Clear Double_Buffer(void) {

// угадали что это?

_fmemset(double_buffer, 0, SCREEN__WIDTH * SCREEN_HEIGHT + 1);

} // конец Clear_Double_Buffer

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

void main(void)

{

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

// и последовательно меняем их до тех пор пока игрок не изменит

// координату Z объекта, нажав клавишу "," или "."

int done=0, // флаг завершения

count=0, // счетчик времени изменения кадра

scale=64; // текущий масштаб спрайта

float scale_distance = 24000, // произвольная константа

// для согласования

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

// пространства

view_distance = 256, // дистанция до объекта

х=0, // позиция корабля в трехмерном

// пространстве

у=0,

z=1024;

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

_setvideomode(_MRES256COLOR);

sprite_width = 80;

sprite_height =48;

 

// создание таблицы для подсистемы масштабирования

Build_Scale_Table ();

// инициализация файла PCX, содержащего кадры

PCX_Init((pcx_picture_ptr)&text cells);

// загрузка файла PCX, содержащего кадры

PCX_Load("vyrentxt.pcx", (pcx_picture_ptr)&text_cells,1);

// резервируем память под дублирующий буфер

Init_Double_Buffer ();

Sprite_Init((sprite_ptr)&object,0,0,0,0,0,0);

// загружаем 12 кадров с космическим кораблем

PCX_Grap_Bitmap ((pcx_picture_ptr) &text_cells,

(sprite_ptr)&object,0,0,0);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,1,1,0);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,2,2,0);

PCX_Grap_Bitmap ((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,3,0,1);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,(sprite_ptr)&object,4,1,1);

PCX_Grap_Bitmap ((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,5,2,1);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,6,0,2);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,7,1,2);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,8,2,2);

PCX_Grap_Bitinap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,9,0,3);

PCX_Grap_Bitmap((pcx_picture_ptr)&text_cells,

(sprite_ptr)&object,10,1,3);

PCX__Grap_Bitmap((pcx_picture_ptr) &text_cells,

(sprite_ptr)&object,11,2,3);

// начальная позиция корабля

object.curr_frame =0;

object.x = 0;

object, у =0;

Clear_Double_Buffer();

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

while(!done)

{

// нажал ли игрок клавишу?

if (kbhit())

{

switch(getch()) {

case '.': // отдаляем корабль

{

z+=16;

} break;

case ',':// приближаем корабль

{

z-=l6;

//не позволяем кораблю подойти слишком близко

if(Z<256)

z=256;

} break;

case 'q': // выход из программы

{

done=1;

} break;

default:break;

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

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

//рассчитываем размер растрового изображения

scale = (int)(scale_distance/z);

// исходя из размера растрового изображения,

// рассчитываем проекции координат Х и Y

object.x= (int)((float)x*view_distance / (float)z) + 160 - (scale>>1);

object.y = 100 - (((int)((float y*view_distanc=e / (float)z) + (scale>>1)));

// увеличиваем счетчик кадров

if (++count==2)

{

count=0;

if (++object.curr_frame==12) object.curr_frame=0;

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

// очищаем дублирующий буфер

Clear_Double_Buffer();

// масштабируем спрайт

Scale_Sprite((sprite_ptr)&object,scale);

Show_Double_Buffer(double_buffer);

// выводим информацию на экран

_settextposition(24,0);

printf("z Coordinate is %f",z);

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

// Удаляем файл PCX

PCX_Delete((pcx_picture_ptr) &text_cells);

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

_setvideomode(_DEFAULTMODE);

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

После выполнения программы из Листинга 8.2, вы, возможно, будете удивлены возможностями оцифровки изображений макетов и приведенным вариантом трехмерной мультипликации. Кто знает, может быть вы создадите что-нибудь именно по типу игры Wing Commander, а вовсе не очередную вариацию DOOM? Однако пора переходить к алгоритму отсечения.

Отсечение спрайтов в трехмерном пространстве

После построения аксонометрической проекции спрайта отсечение выполняется довольно легко. Алгоритм просто тестирует, не выходит ли проекция отмасштабированного спрайта за границы экрана, и, кроме того, проверяет, находится ли Z-координата спрайта внутри наблюдаемой области пространства. Следовательно, проблема отсечения сводится к проверке расположения прямоугольника относительно границ экрана. Решение этой проблемы мы уже рассмотрели раньше (в четвертой главе, «Механизмы двухмерной графики»).

Как вы помните, существует два подхода к этой проблеме: можно использовать алгоритм пространства образов и алгоритм пространства объектов. Первый путь намного проще. Перед обновлением каждого пикселя спрайта, мы проверяем, находится ли он внутри границ экрана (или окна просмотра), и если это так, то замещаем пиксель. Недостаток этого метода — низкая производи тельность (хотя иногда все же приходится прибегать к алгоритму пространства образов из-за чересчур сложной геометрической формы визуализируемого объекта). В общем же случае алгоритм пространства образов работает медленнее алгоритма пространства объектов.

При использовании объектно-пространственного алгоритма мы должны каким-то образом до прорисовки определить, какая часть спрайта будет нарисована и на основании этого вновь вычислить его проекцию. По существу, мы должны отсечь границами экрана прямоугольник, который получается в результате масштабирования спрайта. Это кажется несложным. Мы разбирали текст такой программы в предыдущей главе (Листинг 7.3), но я повторю этот алгоритм еще один раз! Такой уж я.

Алгоритм 8.1 предполагает, что:

§ Экран ограничивается точками (0,0) и (scrfeen_x, screen_y);

§ Верхняя левая точка спрайта (sprifce_x, sprite_y);

§ Спрайт имеет размеры width и height.


Предположим, отсечение пространства по оси Z уже было сделано и внешне образ выглядит вполне правдиво. Пусть также были сосчитаны масштаб объекта и координаты проекций по осям Х и Y.

Date: 2015-09-18; view: 394; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.006 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию