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

Жарков В.А. - Visual C++ 2005, DirectX 9.0c и Microsoft Agent в компьютерной графике, мультимедиа и играх (Листинги книги) - 2005

.pdf
Скачиваний:
306
Добавлен:
13.08.2013
Размер:
1.14 Mб
Скачать

110 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

DesigningLine(D, H, B, -R, -H, 0);

DesigningLine(D, H, -B, -R, -H, 0);

DesigningLine(D, H, -B, -C, -H, -A);

DesigningLine(C, H, -A, -C, -H, -A);

DesigningLine(C, H, -A, -D, -H, -B); Icosahedron_last = NumLines;

}

//Объявляем структуру Line и массивы этой структуры: public struct Line

{

//Объявляем массивы для соединения точек (points): public float[] fr_points;

public float[] to_points;

//Массивы для соединения преобразованных точек: //(transformed (tr) points):

public float[] fr_tr_points; public float[] to_tr_points;

//Создаем и инициализируем массивы, т.е.

//всем пяти элементам каждого массива присваиваем 0: public void Initialize()

{

fr_points = new float[5]; to_points = new float[5]; fr_tr_points = new float[5]; to_tr_points = new float[5];

}

}

//Объявляем массив Lines структуры Line, оператором new //создаем массив из 100 элементов и инициализируем его, //т.е всем элементам этого массива присваиваем значение null: public Line[] Lines = new Line[100];

//Объявляем и инициализируем переменную для индекса массива: public int NumLines = 0;

//Проектируем линию между точками (x1,y1,z1),(x2,y2,z2): public void DesigningLine(float x1, float y1, float z1,

float x2, float y2, float z2)

{

NumLines = NumLines + 1; //Инициализируем и рассчитываем массив: Lines[NumLines].Initialize(); Lines[NumLines].fr_points[1] = x1; Lines[NumLines].fr_points[2] = y1; Lines[NumLines].fr_points[3] = z1; Lines[NumLines].fr_points[4] = 1; Lines[NumLines].to_points[1] = x2; Lines[NumLines].to_points[2] = y2; Lines[NumLines].to_points[3] = z2;

Глава 26. Изображение и управление объектами на VC# и VC++

111

Lines[NumLines].to_points[4] = 1;

}

//Применяем матрицу переноса (translation matrix) //ко всем линиям, используя MatrixApplyFull.

//Преобразование не имеет 0, 0, 0, 1 в последнем столбце: public void TransformAllDataFull(ref float[,] M)

{

TransformDataFull(ref M, 1, NumLines);

}

//Применяем матрицу переноса (translation matrix)

//ко всем выделенным линиям, используя MatrixApplyFull. //Преобразование не имеет 0, 0, 0, 1 в последнем столбце: public void TransformDataFull(ref float[,] M,

int line1, int line2)

{

for (int i = line1; i <= line2; i++)

{

MatrixApplyFull(ref Lines[i].fr_points, ref M, ref Lines[i].fr_tr_points);

MatrixApplyFull(ref Lines[i].to_points, ref M, ref Lines[i].to_tr_points);

}

}

//Перем-я N_Graphics для номера многих геом-х изобр-й. //Номер первого изображения равен 1:

int N_Graphics = 1;

//Рисуем преобразованные линии геометрического объекта: public void DrawSolid(Bitmap bmp,

int first_line, int last_line, Color color, bool clear)

{

float x1, y1, x2, y2; Graphics g; Pen pen;

//Задаем толщину линии рисования, например, 2 //(цвет линии мы задали в методе Designing): pen = new Pen(color, 2);

//Связываем объект g с изображением bmp: g = Graphics.FromImage(bmp);

if (clear) g.Clear(System.Drawing.Color.Black); //Объявляем индексы элементов всех массивов: int i, j, k;

//Если этот метод DrawSolid вызван второй раз

//для рисования второго изображения и N_Graphics = 2, //то обходим 1-й массив для первого изобр-я до метки M2: if (N_Graphics == 2) goto M2;

//Программируем первый массив для первого изображения. //Задаем границы индексов первого массива myArray[i, j]: int N_x = 200;

112 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

int N_y = 2;

//Объявляем массив myArray[i, j] переменных типа float, //i = 0,1,2,3,...,(N_x-1); j = 0,1,2,3,...,(N_y-1): float[,] myArray = new float[N_x, N_y];//Обнуляется. //Значение первой границы массива myArray:

int N_1_myArray;

//Рассчитываем элементы массива myArray(i, j) //для рисования линий первого геом-го изображения: i = -1; //Задаем до цикла.

for (k = first_line; k <= last_line; k++)

{

x1 = Lines[k].fr_tr_points[1];

y1 = Lines[k].fr_tr_points[2];

x2 = Lines[k].to_tr_points[1];

y2 = Lines[k].to_tr_points[2];

//Можно рисовать линии изображения и здесь: //g.DrawLine(pen,

//(x1 * bmp.Width / 4) + bmp.Width / 2.0F,

//bmp.Height / 2.0F - (y1 * bmp.Height / 4),

//(x2 * bmp.Width / 4) + bmp.Width / 2.0F,

//bmp.Height / 2.0F - (y2 * bmp.Height / 4)); //Масштабируем значения координат:

x1 = (x1 * bmp.Width / 4) + bmp.Width / 2.0F; y1 = bmp.Height / 2.0F - (y1 * bmp.Height / 4); x2 = (x2 * bmp.Width / 4) + bmp.Width / 2.0F; y2 = bmp.Height / 2.0F - (y2 * bmp.Height / 4); //Записываем координаты точек в массив:

i= i + 2;

myArray[i, 0] = x1; myArray[i, 1] = y1; myArray[i + 1, 0] = x2; myArray[i + 1, 1] = y2;

N_1_myArray = i + 1; //Значение границы массива.

}

//Начало N_first_line и конец N_last_line цикла

//при рисовании из массива myArray: int N_first_line, N_last_line; N_first_line = first_line; N_last_line = last_line;

//Передаем значения начала N_first_line

//и конца цикла N_last_line в элементы массива

//myArray[0, 0] и myArray[0, 1]: myArray[0, 0] = N_first_line; myArray[0, 1] = N_last_line;

//Рисуем при помощи массива координат myArray[200, 2]. i = -1;

for (k = N_first_line; k <= N_last_line; k++)

Глава 26. Изображение и управление объектами на VC# и VC++

113

{

 

 

i = i + 2;

 

x1

= myArray[i, 0];

 

y1

= myArray[i, 1];

 

x2

= myArray[i + 1, 0];

 

y2

= myArray[i + 1, 1];

 

g.DrawLine(pen, x1, y1, x2, y2);

}

//Записываем массив координат myArray(200, 1) в файл. //Создаем объект sw класса StreamWriter для записи

//в файл по адресу D:\MyDocs\MyTest3D_Graphics.txt. if (N_Graphics == 1)

{

StreamWriter sw = new StreamWriter( @"D:\MyDocs\MyTest3D_Graphics.txt");

//Каждый элемент myArray[i, j] записываем в файл //в виде отдельной строки при помощи WriteLine: for (i = 0; i <= N_x-1; i++)

for (j = 0; j <= N_y-1; j++) sw.WriteLine(myArray[i, j]);

sw.Close();

}

M2:

//Если этот метод DrawSolid вызван первый раз

//для рисования первого изображения и N_Graphics = 1, //то обходим 2-й массив для 2-го изобр-я до метки M_End: if (N_Graphics == 1) goto M_End;

//Программируем второй массив для второго изображения. //Задаем границы индексов 2-го массива myArray_2(i, j): int N_x_2 = 200;

int N_y_2 = 2;

//Задаем массив myArray_2(i, j) переменных типа Single, //когда i = 0,1,2,3,...,(N_x-1); j = 0,1,2,3,...,(N_y-1): float[,] myArray_2 = new float[N_x_2,

N_y_2];//Обнуляется.

//Значение первой границы массива myArray_2: int N_1_myArray_2;

//Рассчитываем элементы массива myArray_2(i, j) //для рисования линий второго геом-го изображения: i = -1; //Задаем до цикла.

for (k = first_line; k <= last_line; k++)

{

x1 = Lines[k].fr_tr_points[1];

y1 = Lines[k].fr_tr_points[2];

x2 = Lines[k].to_tr_points[1];

y2 = Lines[k].to_tr_points[2];

114 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

//Можно рисовать линии изображения и здесь: //g.DrawLine(pen,

//(x1 * bmp.Width / 4) + bmp.Width / 2.0F,

//bmp.Height / 2.0F - (y1 * bmp.Height / 4),

//(x2 * bmp.Width / 4) + bmp.Width / 2.0F,

//bmp.Height / 2.0F - (y2 * bmp.Height / 4)); //Масштабируем значения координат:

x1 = (x1 * bmp.Width / 4) + bmp.Width / 2.0F; y1 = bmp.Height / 2.0F - (y1 * bmp.Height / 4); x2 = (x2 * bmp.Width / 4) + bmp.Width / 2.0F; y2 = bmp.Height / 2.0F - (y2 * bmp.Height / 4); //Записываем координаты точек в массив:

i = i + 2; myArray_2[i, 0] = x1; myArray_2[i, 1] = y1;

myArray_2[i + 1, 0] = x2; myArray_2[i + 1, 1] = y2;

N_1_myArray_2 = i + 1;//Граница массива.

}

//Начало N_first_line_2 и конец N_last_line_2 цикла

//при рисовании из массива myArray_2: int N_first_line_2, N_last_line_2; N_first_line_2 = first_line; N_last_line_2 = last_line;

//Передаем значения начала N_first_line_2

//и конца цикла N_last_line_2 в элементы массива

//myArray_2[0, 0] и myArray_2[0, 1]: myArray_2[0, 0] = N_first_line_2; myArray_2[0, 1] = N_last_line_2;

//Рисуем при помощи массива координат myArray_2[200, 1]: i = -1;

for (k = N_first_line_2; k <= N_last_line_2; k++)

{

i = i + 2;

x1 = myArray_2[i, 0];

y1 = myArray_2[i, 1];

x2 = myArray_2[i + 1, 0];

y2 = myArray_2[i + 1, 1]; g.DrawLine(pen, x1, y1, x2, y2);

}

//Записываем массив координат myArray_2[200, 1] в файл. //Создаем объект sw_2 класса StreamWriter для записи

//в файл по адресу D:\MyDocs\MyTest3D_Graphics_2.txt. //Файл автоматически очищается:

StreamWriter sw_2 = new StreamWriter( @"D:\MyDocs\MyTest3D_Graphics_2.txt");

//Каждый элемент myArray_2[i, j] запис-м в файл

Глава 26. Изображение и управление объектами на VC# и VC++

115

//в виде отдельной строки при помощи WriteLine: for (i = 0; i <= N_x_2-1; i++)

for (j = 0; j <= N_y_2-1; j++) sw_2.WriteLine(myArray_2[i, j]);

sw_2.Close();

//Высвобождаем ресурсы от объектов g и pen: g.Dispose(); pen.Dispose();

M_End:

//Если этот метод DrawSolid вызван еще раз //для рисования следующего изображения,

//то увеличиваем номер изображения N_Graphics на 1: N_Graphics = N_Graphics + 1;

}

//Строим единичную матрицу:

public void MatrixIdentity(ref float[,] M)

{

for (int i = 1; i <= 4; i++)

{

for (int j = 1; j <= 4; j++)

{

if (i == j) M[i, j] = 1; else M[i, j] = 0;

}

}

}

//Строим матрицу преобразования (3-D transformation matrix) //для перспективной проекции вдоль оси z на плоскость x,y //с центром объекта (фокусом) в начале координат

//и c центром проецирования на расстоянии (0, 0, Distance): public void MatrixPerspectiveXZ(ref float[,] M,

float Distance)

{

MatrixIdentity(ref M);

if (Distance != 0) M[3, 4] = -1 / Distance;

}

//Строим матрицу преобразования (3-D transformation matrix) //для проецирования с координатами:

//центр проецирования (cx, cy, cz), фокус (fx, fy, fx), //вектор от объекта до экрана UP <ux, yx, uz>,

//тип проецирования (type_of_projection): //PerspectiveProjection или ParallelProjection: public void MatrixTransformation(ref float[,] M, int type_of_projection,

float Cx, float Cy, float Cz, float Fx, float Fy, float Fz, float ux, float uy, float uz)

{

116 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

float[,] M1 = new float[5, 5]; float[,] M2 = new float[5, 5]; float[,] M3 = new float[5, 5]; float[,] M4 = new float[5, 5]; float[,] M5 = new float[5, 5]; float[,] M12 = new float[5, 5]; float[,] M34 = new float[5, 5]; float[,] M1234 = new float[5, 5];

float sin1 = 0, cos1 = 0; float sin2 = 0, cos2 = 0; float sin3, cos3; float A, B, C; float d1, d2, d3; float[] up1 = new float[5]; float[] up2 = new float[5]; //Переносим фокус (центр объекта) в начало координат: MatrixTranslate(ref M1, -Fx, -Fy, -Fz);

A = Cx - Fx; B = Cy - Fy; C = Cz - Fz;

d1 = (float)Math.Sqrt(A * A + C * C); if (d1 != 0)

{

sin1 = -A / d1; cos1 = C / d1;

}

d2 = (float)Math.Sqrt(A * A + B * B + C * C); if (d2 != 0)

{

sin2 = B / d2; cos2 = d1 / d2;

}

//Вращаем объект вокруг оси y, чтобы разместить //центр проекции в y-z плоскости: MatrixIdentity(ref M2);

//Если d1 = 0, тогда центр проекции

//уже находится на оси y и в y-z плоскости: if (d1 != 0)

{

M2[1, 1] = cos1; M2[1, 3] = -sin1; M2[3, 1] = sin1; M2[3, 3] = cos1;

}

//Вращаем вокруг оси x,

//чтобы разместить центр проекции на оси z: MatrixIdentity(ref M3);

//Если d2 = 0, то центр проекции //находится в начале координат. //Это делает проекцию невозможной: if (d2 != 0)

{

M3[2, 2] = cos2; M3[2, 3] = sin2; M3[3, 2] = -sin2; M3[3, 3] = cos2;

}

//Вращаем вектор UP:

up1[1] = ux; up1[2] = uy; up1[3] = uz;

Глава 26. Изображение и управление объектами на VC# и VC++

117

up1[4] = 1;

MatrixApply(ref up1, ref M2, ref up2); MatrixApply(ref up2, ref M3, ref up1); //Вращаем вокруг оси z, чтобы разместить //вектор UP в y-z плоскости:

d3 = (float)Math.Sqrt(up1[1] * up1[1] + up1[2] * up1[2]);

MatrixIdentity(ref M4);

//Если d3 = 0, то вектор UP равен нулю: if (d3 != 0)

{

sin3 = up1[1] / d3; cos3 = up1[2] / d3; M4[1, 1] = cos3; M4[1, 2] = sin3; M4[2, 1] = -sin3; M4[2, 2] = cos3;

}

//Проецируем:

if (type_of_projection == PerspectiveProjection) MatrixPerspectiveXZ(ref M5, d2);

else

MatrixIdentity(ref M5); if (d2 != 0)

MatrixPerspectiveXZ(ref M5, d2); else

MatrixIdentity(ref M5); //Комбинируем преобразования: m3MatMultiply(ref M12, ref M1, ref M2); m3MatMultiply(ref M34, ref M3, ref M4);

m3MatMultiply(ref M1234, ref M12, ref M34);

if (type_of_projection == PerspectiveProjection) m3MatMultiplyFull(ref M, ref M1234, ref M5);

else

m3MatMultiply(ref M, ref M1234, ref M5);

}

//Строим матрицу преобразования (3-D transformation matrix) //для перспективного проецирования (perspective projection): //центр проецирования (r, phi, theta),

//фокус (fx, fy, fx),

//вектор от объекта до экрана UP <ux, yx, uz>, //тип проецирования (type_of_projection): //PerspectiveProjection:

public void Projection(ref float[,] M, int type_of_projection, float R, float phi, float theta,

float Fx, float Fy, float Fz, float ux, float uy, float uz)

{

float Cx, Cy, Cz, r2;

118 Жарков В.А. Компьютерная графика, мультимедиа и игры на Visual C++ 2005

//Переходим к прямоугольным координатам: Cy = R * (float)Math.Sin(phi);

r2 = R * (float)Math.Cos(phi); Cx = r2 * (float)Math.Cos(theta); Cz = r2 * (float)Math.Sin(theta);

MatrixTransformation(ref M, type_of_projection, Cx, Cy, Cz, Fx, Fy, Fz, ux, uy, uz); //ref M

}

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

//через (p1, p2, p3) с вектором нормали <n1, n2, n3>: public void m3Reflect(ref float[,] M,

float p1, float p2, float p3, float n1, float n2, float n3)

{

float[,] T = new float[5, 5]; //Перенос. float[,] R1 = new float[5, 5]; //Вращение 1. float[,] r2 = new float[5, 5]; //Вращение 2. float[,] S = new float[5, 5]; //Отражение. float[,] R2i = new float[5, 5]; //Не вращать 2. float[,] R1i = new float[5, 5]; //Не вращать 1. float[,] Ti = new float[5, 5]; //Не переносить. float D, L;

float[,] M12 = new float[5, 5]; float[,] M34 = new float[5, 5]; float[,] M1234 = new float[5, 5]; float[,] M56 = new float[5, 5]; float[,] M567 = new float[5, 5];

//Переносим плоскость к началу координат: MatrixTranslate(ref T, -p1, -p2, -p3); MatrixTranslate(ref Ti, p1, p2, p3); //Вращаем вокруг оси z,

//пока нормаль не будет в y-z плоскости: MatrixIdentity(ref R1);

D = (float)Math.Sqrt(n1 * n1 + n2 * n2); R1[1, 1] = n2 / D; R1[1, 2] = n1 / D; R1[2, 1] = -R1[1, 2]; R1[2, 2] = R1[1, 1]; MatrixIdentity(ref R1i);

R1i[1, 1] = R1[1, 1]; R1i[1, 2] = -R1[1, 2]; R1i[2, 1] = -R1[2, 1]; R1i[2, 2] = R1[2, 2];

//Вращаем вокруг оси x, когда нормаль будет по оси y: MatrixIdentity(ref r2);

L = (float)Math.Sqrt(n1 * n1 + n2 * n2 + n3 * n3); r2[2, 2] = D / L; r2[2, 3] = -n3 / L;

r2[3, 2] = -r2[2, 3]; r2[3, 3] = r2[2, 2]; MatrixIdentity(ref R2i);

R2i[2, 2] = r2[2, 2]; R2i[2, 3] = -r2[2, 3];

Глава 26. Изображение и управление объектами на VC# и VC++

119

R2i[3, 2] = -r2[3, 2]; R2i[3, 3] = r2[3, 3];

//Рисуем отражение объекта перпендикулярно x-z плоскости: MatrixIdentity(ref S); S[2, 2] = -1;

//Комбинируем матрицы: m3MatMultiply(ref M12, ref T, ref R1); m3MatMultiply(ref M34, ref r2, ref S);

m3MatMultiply(ref M1234, ref M12, ref M34); m3MatMultiply(ref M56, ref R2i, ref R1i); m3MatMultiply(ref M567, ref M56, ref Ti); m3MatMultiply(ref M, ref M1234, ref M567);

}

//Строим матрицу преобразования для поворота на угол theta //вокруг линии, проходящей через (p1, p2, p3)

//в направлении <d1, d2, d3>.

//Угол theta откладывается против часовой стрелки, //если мы смотрим вниз в направлении, //противоположном направлению линии:

public void m3LineRotate(ref float[,] M, float p1, float p2, float p3,

float d1, float d2, float d3, float theta)

{

float[,] T = new float[5, 5]; //Перенос. float[,] R1 = new float[5, 5]; //Вращение 1. float[,] r2 = new float[5, 5]; //Вращение 2. float[,] Rot3 = new float[5, 5]; //Вращение.

float[,] R2i = new float[5, 5]; //Стоп вращению 2. float[,] R1i = new float[5, 5]; //Стоп вращению 1. float[,] Ti = new float[5, 5]; //Стоп переносу. float D, L;

float[,] M12 = new float[5, 5]; float[,] M34 = new float[5, 5]; float[,] M1234 = new float[5, 5]; float[,] M56 = new float[5, 5]; float[,] M567 = new float[5, 5];

//Переносим плоскость к началу координат: MatrixTranslate(ref T, -p1, -p2, -p3); MatrixTranslate(ref Ti, p1, p2, p3); //Вращаем вокруг оси z,

//пока линия не окажется в y-z плоскости: MatrixIdentity(ref R1);

D = (float)Math.Sqrt(d1 * d1 + d2 * d2); R1[1, 1] = d2 / D; R1[1, 2] = d1 / D; R1[2, 1] = -R1[1, 2]; R1[2, 2] = R1[1, 1]; MatrixIdentity(ref R1i);

R1i[1, 1] = R1[1, 1]; R1i[1, 2] = -R1[1, 2]; R1i[2, 1] = -R1[2, 1]; R1i[2, 2] = R1[2, 2];

//Вращаем вокруг оси x, когда линия будет по оси y:

Соседние файлы в предмете Программирование на C++