Жарков В.А. - Visual C++ 2005, DirectX 9.0c и Microsoft Agent в компьютерной графике, мультимедиа и играх (Листинги книги) - 2005
.pdf110 Жарков В.А. Компьютерная графика, мультимедиа и игры на 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: