Lab03 - Nguyen Đuc Hoai Vu - 102220048

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 48

BÀI THỰC HÀNH ĐỒ HỌA MÁY TÍNH

MA TRẬN CÁC PHÉP ĐỔI AFFINE

Nhóm học phần:


Mã Sinh viên, Họ và Tên: 102220048 Nguyễn Đức Hoài Vũ

1. lab03AffineMatrix.cpp..........................................................................................1
2. labmatrixCG - Thực hiện các phép biến đổi affine thông qua các hàm tự xây
dựng 7
2.1 Vectors.h.........................................................................................................................7
2.2 Matrices.h.....................................................................................................................14
2.3 main.cpp........................................................................................................................23
3. BÀI TẬP................................................................................................................40

1. lab03AffineMatrix.cpp
#include <math.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>

typedef float Matrix4x4[4][4];


Matrix4x4 Matrix;

//Khoi tao cac bien toan cuc


//Khoi tao mang chua toa do cac dinh cua hinh lap phuong
float points[8][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0,
0}, {0, 0, 0}};
float pointsFin[8][3]; //Mang cac toa do sau khi bien doi
float TransDistX, TransDistY, TransDistZ; //Tinh tien theo huong X, Y, Z
float ScaleX, ScaleY, ScaleZ; //Ty le theo X, Y, Z
float Theta; //Goc quay
float x, y, z;
float x1, y11, z1, x2, y2, z2;
int choice, choiceRef;

//Tinh toan toa do cac dinh


void inputPoint(float a)
{
points[0][0] = 2 * a + 10;
points[0][1] = 2 * a + 10;
points[0][2] = 2 * a + 10;

points[1][0] = 10;
points[1][1] = 2 * a + 10;
points[1][2] = 2 * a + 10;

points[2][0] = 10;
points[2][1] = 10;
points[2][2] = 2 * a + 10;

points[3][0] = 2 * a + 10;
points[3][1] = 10;
points[3][2] = 2 * a + 10;

points[4][0] = 2 * a + 10;
points[4][1] = 2 * a + 10;

KhoaCNTT – Trường ĐHBK 1


points[4][2] = 10;

points[5][0] = 10;
points[5][1] = 2 * a + 10;
points[5][2] = 10;

points[6][0] = 10;
points[6][1] = 10;
points[6][2] = 10;

points[7][0] = 2 * a + 10;
points[7][1] = 10;
points[7][2] = 10;
}

// Khoi tao ma tran don vi


void matrixSetIdentity(Matrix4x4 m)
{
int i, j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
m[i][j] = (i == j);
}
}
}

// Nhan 2 ma tran a, b; Gan ket qua vao ma tran b


void matrixMul(Matrix4x4 a, Matrix4x4 b)
{
int i, j;
Matrix4x4 tmp;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
tmp[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j] + a[i][3] * b[3][j];
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
Matrix[i][j] = tmp[i][j];
}
}
}

//In ma tran
void printMatrix(Matrix4x4 b){
for (int i=0;i<4;i++){
std::cout << std::endl << std::setw(5) << "|" << std::setw(10);
for (int j=0;j<4;j++){
std::cout << std::setw(10);
std::cout << b[i][j];
if(j==3) std::cout << std::setw(3)<< "|";
}
}
std::cout << std::endl << std::endl;
}

//In toa do cac dinh cua khoi lap phuong


void printPoint(float a[8][3]){

for (int i=0;i<8;i++){


std::cout << std::fixed;
std::cout << std::setprecision(2);
std::cout << std::setw(10) << "Dinh " << (i+1) << ": ";
std::cout << "(" << std::setw(3);
for (int j=0;j<3;j++){
std::cout << std::setw(10);
std::cout << a[i][j];
if(j==2) std::cout << std::setw(3)<< ")" << std::endl;
else std::cout << ",";
}
}
std::cout << std::endl;
}

KhoaCNTT – Trường ĐHBK 2


//Bien doi tinh tien
void Translate(int tx, int ty, int tz)
{
Matrix4x4 m;
matrixSetIdentity(m);
m[0][3] = tx;
m[1][3] = ty;
m[2][3] = tz;
matrixMul(m, Matrix);
printf("Ma tran tinh tien:");
printMatrix(Matrix);
}

//Bien doi ty le
void Scale(float sx, float sy, float sz)
{
Matrix4x4 m;
matrixSetIdentity(m);
m[0][0] = sx;
m[1][1] = sy;
m[2][2] = sz;
matrixMul(m, Matrix);
printf("Ma tran ty le:");
printMatrix(m);
}

//Bien doi quay theo truc X


void RotateX(float angle)
{
Matrix4x4 m;
matrixSetIdentity(m);
angle = angle * 22 / 1260;
m[1][1] = cos(angle);
m[1][2] = -sin(angle);
m[2][1] = sin(angle);
m[2][2] = cos(angle);
matrixMul(m, Matrix);
printf("Ma tran quay theo X:");
printMatrix(m);
}

//Bien doi quay theo truc Y


void RotateY(float angle)
{
Matrix4x4 m;
matrixSetIdentity(m);
angle = angle * 22 / 1260;
m[0][0] = cos(angle);
m[0][2] = sin(angle);
m[2][0] = -sin(angle);
m[2][2] = cos(angle);
matrixMul(m, Matrix);
printf("Ma tran quay theo Y:");
printMatrix(m);
}

//Bien doi quay theo truc Z


void RotateZ(float angle)
{
Matrix4x4 m;
matrixSetIdentity(m);
angle = angle * 22 / 1260;
m[0][0] = cos(angle);
m[0][1] = -sin(angle);
m[1][0] = sin(angle);
m[1][1] = cos(angle);
matrixMul(m, Matrix);
printf("Ma tran quay theo Z:");
printMatrix(m);
}

//Bien doi doi xung


void Reflect(void)
{
Matrix4x4 m;
matrixSetIdentity(m);
switch (choiceRef)
{
case 1:
m[2][2] = -1;

KhoaCNTT – Trường ĐHBK 3


break;
case 2:
m[0][0] = -1;
break;
case 3:
m[1][1] = -1;
break;
}
matrixMul(m, Matrix);
printf("Ma tran doi xung:");
printMatrix(m);
}

//Ve duong thang di qua A(x1,y11,z1) va B(x2,y2,z2)


void DrawRotLine(void)
{
glBegin(GL_LINES);
glColor3f(1.0f, 1.0f, 0.0f);
glLineWidth(10.0f);
glVertex3s(x1 - x * 500, y11 - y * 500, z1 - z * 500);
glVertex3s(x2 + x * 500, y2 + y * 500, z2 + z * 500);
glEnd();
}

//Bien doi toa do cac dinh theo yeu cau (tinh tien, ty le, quay, doi xung)
void TransPoints(void)
{
int i, k;
float tmp;
for (k = 0; k < 8; k++)
for (i = 0; i < 3; i++)
pointsFin[k][i] = Matrix[i][0] * points[k][0] + Matrix[i][1] * points[k][1] +
Matrix[i][2] * points[k][2] + Matrix[i][3];

printf("\tCac dinh sau bien doi: \n");


printPoint(pointsFin);
}

//Ve cac truc toa do


void drawCoordinateAxisZ()
{
glLineWidth(2.0f);
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 2000.0f);
glEnd();
glLineWidth(1.0f);
}

void drawCoordinateAxisX()
{
glPushMatrix();
glRotatef(90.0f, 0.0f, 2000.0f, 0.0f);
drawCoordinateAxisZ();
glPopMatrix();
}

void drawCoordinateAxisY()
{
glPushMatrix();
glRotatef(-90.0f, 2000.0f, 0.0f, 0.0f);
drawCoordinateAxisZ();
glPopMatrix();
}

void drawFrame()
{
glLineWidth(2.0f);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glColor3f(0.0f, 0.0f, 0.0f);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glLineWidth(1.0f);
}

//Ve cac truc toa do


void drawCoordinateAxis()
{

KhoaCNTT – Trường ĐHBK 4


glColor3f(0.0f, 0.0f, 1.0f);
drawCoordinateAxisZ();
glColor3f(0.0f, 1.0f, 0.0f);
drawCoordinateAxisY();
glColor3f(1.0f, 0.0f, 0.0f);
drawCoordinateAxisX();
}

//Ve khoi lap phuong theo toa do cac dinh


void Draw(float a[8][3])
{
int i;
glColor3f(0.7, 0.4, 0.7);
glBegin(GL_POLYGON);
glVertex3f(a[0][0], a[0][1], a[0][2]);
glVertex3f(a[1][0], a[1][1], a[1][2]);
glVertex3f(a[2][0], a[2][1], a[2][2]);
glVertex3f(a[3][0], a[3][1], a[3][2]);
glEnd();

i = 0;
glColor3f(0.8, 0.6, 0.5);
glBegin(GL_POLYGON);
glVertex3s(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3s(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3s(a[5 + i][0], a[5 + i][1], a[5 + i][2]);
glVertex3s(a[4 + i][0], a[4 + i][1], a[4 + i][2]);
glEnd();
glColor3f(0.2, 0.4, 0.7);
glBegin(GL_POLYGON);
glVertex3f(a[0][0], a[0][1], a[0][2]);
glVertex3f(a[3][0], a[3][1], a[3][2]);
glVertex3f(a[7][0], a[7][1], a[7][2]);
glVertex3f(a[4][0], a[4][1], a[4][2]);
glEnd();

i = 1;
glColor3f(0.5, 0.4, 0.3);
glBegin(GL_POLYGON);
glVertex3s(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3s(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3s(a[5 + i][0], a[5 + i][1], a[5 + i][2]);
glVertex3s(a[4 + i][0], a[4 + i][1], a[4 + i][2]);
glEnd();

i = 2;
glColor3f(0.5, 0.6, 0.2);
glBegin(GL_POLYGON);
glVertex3s(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3s(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3s(a[5 + i][0], a[5 + i][1], a[5 + i][2]);
glVertex3s(a[4 + i][0], a[4 + i][1], a[4 + i][2]);
glEnd();

i = 4;
glColor3f(0.7, 0.3, 0.4);
glBegin(GL_POLYGON);
glVertex3f(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3f(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3f(a[2 + i][0], a[2 + i][1], a[2 + i][2]);
glVertex3f(a[3 + i][0], a[3 + i][1], a[3 + i][2]);
glEnd();
}

//Hien thi
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawFrame();
gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
drawCoordinateAxis();
glColor3f(1.0, 0.0, 0.0);
Draw(points);
matrixSetIdentity(Matrix);

switch (choice)
{
case 1:
Translate(TransDistX, TransDistY, TransDistZ);
break;

KhoaCNTT – Trường ĐHBK 5


case 2:
Scale(ScaleX, ScaleY, ScaleZ);
Translate(0, 0, 300);
break;
case 3:
{
DrawRotLine();
float MOD = sqrt((x2 - x1) * (x2 - x1) + (y2 - y11) * (y2 - y11) + (z2 - z1) * (z2 -
z1));
x = (x2 - x1) / MOD;
y = (y2 - y11) / MOD;
z = (z2 - z1) / MOD;
Translate(-x1, -y11, -z1);
float ThetaDash;
ThetaDash = 1260 * atan(y / z) / 22;
RotateX(ThetaDash);
RotateY(1260 * asin(-x) / 22);
RotateZ(Theta);
printf("Bien doi nguoc lai:\n");
RotateY(1260 * asin(x) / 22);
RotateX(-ThetaDash);
Translate(x1, y11, z1);
break;
}
case 4:
Reflect();
break;
}
TransPoints();
Draw(pointsFin);
glFlush();
}

//Khoi tao
void init(void)
{
glOrtho(-1000.0, 1000.0, -500.0, 500.0, -500.0, 500.0);
glEnable(GL_DEPTH_TEST); //Hien thi theo chieu sau cua vat the
}

int main(int argc, char *argv)


{
glutInit(&argc, &argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(1362, 750);
glutInitWindowPosition(0, 0);
glutCreateWindow("Nhom 2 - Dinh Man - The Nam");
init();

//Nhap canh
float a;
printf("Nhap do dai canh: ");
scanf("%f", &a);
inputPoint(a/2.0);
printf("\tCac dinh ban dau:\n");
printPoint(points);

printf("Chon phep bien doi:\n1.Tinh tien\n2.Ty le\n3.Quay\n4.Doi xung\n=>");


scanf("%d", &choice);
switch (choice)
{
case 1:
printf("Nhap gia tri tinh tien theo X, Y, Z\n=>");
scanf("%f%f%f", &TransDistX, &TransDistY, &TransDistZ);
break;
case 2:
printf("Nhap gia tri ty le theo X, Y, Z\n=>");
scanf("%f%f%f", &ScaleX,&ScaleY, &ScaleZ);
break;
case 3:
printf("Nhap toa do 2 diem (x1,y1,z1) & (x2,y2,z2)\n =>");
printf("Nhap gia tri x1 ,y1, z1:\n");
scanf("%f %f %f", &x1, &y11, &z1);
printf(" Nhap gia tri x2 ,y2, z2:\n");
scanf("%f %f %f", &x2, &y2, &z2);
printf("Nhap gia tri goc quay: ");
scanf("%f", &Theta);
break;
case 4:
printf("Chon mat phang doi xung:\n1.Oxy\n2.Oyz\n3.Oxz\n=>");

KhoaCNTT – Trường ĐHBK 6


scanf("%d", &choiceRef);
break;
default:
printf("Gia tri khong hop le!!!\n");
return 0;
}
glutDisplayFunc(display);
glutMainLoop();
return 0;
}//main

Kết quả thực hiện

 Kết quả đối với phép tịnh tiến Ma trận biến đổi : Hình ảnh sau khi biến đổi tịnh tiến
theo trục X

KhoaCNTT – Trường ĐHBK 7


 Hình ảnh phép quay quanh đường thẳng PQ với P(0, 300, 400) và Q(200, 200, 0), góc
quay 500

KhoaCNTT – Trường ĐHBK 8


KhoaCNTT – Trường ĐHBK 9
 Hình ảnh phép quay quanh đường thẳng PQ với P(0, 300, 400) và Q(200, 200, 0), góc
quay 500

KhoaCNTT – Trường ĐHBK 10


Hình ảnh đổi xứng qua mặt phẳng Oxy

KhoaCNTT – Trường ĐHBK 11


2. labmatrixCG - Thực hiện các phép biến đổi affine thông qua các hàm
tự xây dựng
Tải file matrixCG.rar từ LINK01 về và giải nén
hoặc tạo mới một thư mục matrixCG có các file sau:
2.1 Vectors.h
///////////////////////////////////////////////////////////////////////////////
// Vectors.h
// =========
// 2D/3D/4D vectors
///////////////////////////////////////////////////////////////////////////////

#ifndef VECTORS_H_DEF
#define VECTORS_H_DEF

#include <cmath>
#include <iostream>

///////////////////////////////////////////////////////////////////////////////
// 2D vector
///////////////////////////////////////////////////////////////////////////////
struct Vector2
{
float x;
float y;

// ctors
Vector2() : x(0), y(0) {};
Vector2(float x, float y) : x(x), y(y) {};

// utils functions
void set(float x, float y);
float length() const; //
float distance(const Vector2& vec) const; // distance between two vectors
Vector2& normalize(); //
float dot(const Vector2& vec) const; // dot product
bool equal(const Vector2& vec, float e) const; // compare with epsilon

// operators
Vector2 operator-() const; // unary operator (negate)
Vector2 operator+(const Vector2& rhs) const; // add rhs
Vector2 operator-(const Vector2& rhs) const; // subtract rhs
Vector2& operator+=(const Vector2& rhs); // add rhs and update this object
Vector2& operator-=(const Vector2& rhs); // subtract rhs and update this object
Vector2 operator*(const float scale) const; // scale
Vector2 operator*(const Vector2& rhs) const; // multiply each element
Vector2& operator*=(const float scale); // scale and update this object
Vector2& operator*=(const Vector2& rhs); // multiply each element and update
this object
Vector2 operator/(const float scale) const; // inverse scale
Vector2& operator/=(const float scale); // scale and update this object
bool operator==(const Vector2& rhs) const; // exact compare, no epsilon
bool operator!=(const Vector2& rhs) const; // exact compare, no epsilon
bool operator<(const Vector2& rhs) const; // comparison for sort
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]

friend Vector2 operator*(const float a, const Vector2 vec);


friend std::ostream& operator<<(std::ostream& os, const Vector2& vec);
};

///////////////////////////////////////////////////////////////////////////////
// 3D vector
///////////////////////////////////////////////////////////////////////////////
struct Vector3
{
float x;
float y;
float z;

// ctors
Vector3() : x(0), y(0), z(0) {};
Vector3(float x, float y, float z) : x(x), y(y), z(z) {};

KhoaCNTT – Trường ĐHBK 12


// utils functions
void set(float x, float y, float z);
float length() const; //
float distance(const Vector3& vec) const; // distance between two vectors
Vector3& normalize(); //
float dot(const Vector3& vec) const; // dot product
Vector3 cross(const Vector3& vec) const; // cross product
bool equal(const Vector3& vec, float e) const; // compare with epsilon

// operators
Vector3 operator-() const; // unary operator (negate)
Vector3 operator+(const Vector3& rhs) const; // add rhs
Vector3 operator-(const Vector3& rhs) const; // subtract rhs
Vector3& operator+=(const Vector3& rhs); // add rhs and update this object
Vector3& operator-=(const Vector3& rhs); // subtract rhs and update this object
Vector3 operator*(const float scale) const; // scale
Vector3 operator*(const Vector3& rhs) const; // multiplay each element
Vector3& operator*=(const float scale); // scale and update this object
Vector3& operator*=(const Vector3& rhs); // product each element and update
this object
Vector3 operator/(const float scale) const; // inverse scale
Vector3& operator/=(const float scale); // scale and update this object
bool operator==(const Vector3& rhs) const; // exact compare, no epsilon
bool operator!=(const Vector3& rhs) const; // exact compare, no epsilon
bool operator<(const Vector3& rhs) const; // comparison for sort
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]

friend Vector3 operator*(const float a, const Vector3 vec);


friend std::ostream& operator<<(std::ostream& os, const Vector3& vec);
};

///////////////////////////////////////////////////////////////////////////////
// 4D vector
///////////////////////////////////////////////////////////////////////////////
struct Vector4
{
float x;
float y;
float z;
float w;

// ctors
Vector4() : x(0), y(0), z(0), w(0) {};
Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {};

// utils functions
void set(float x, float y, float z, float w);
float length() const; //
float distance(const Vector4& vec) const; // distance between two vectors
Vector4& normalize(); //
float dot(const Vector4& vec) const; // dot product
bool equal(const Vector4& vec, float e) const; // compare with epsilon

// operators
Vector4 operator-() const; // unary operator (negate)
Vector4 operator+(const Vector4& rhs) const; // add rhs
Vector4 operator-(const Vector4& rhs) const; // subtract rhs
Vector4& operator+=(const Vector4& rhs); // add rhs and update this object
Vector4& operator-=(const Vector4& rhs); // subtract rhs and update this object
Vector4 operator*(const float scale) const; // scale
Vector4 operator*(const Vector4& rhs) const; // multiply each element
Vector4& operator*=(const float scale); // scale and update this object
Vector4& operator*=(const Vector4& rhs); // multiply each element and update
this object
Vector4 operator/(const float scale) const; // inverse scale
Vector4& operator/=(const float scale); // scale and update this object
bool operator==(const Vector4& rhs) const; // exact compare, no epsilon
bool operator!=(const Vector4& rhs) const; // exact compare, no epsilon
bool operator<(const Vector4& rhs) const; // comparison for sort
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]

friend Vector4 operator*(const float a, const Vector4 vec);


friend std::ostream& operator<<(std::ostream& os, const Vector4& vec);
};

KhoaCNTT – Trường ĐHBK 13


// fast math routines from Doom3 SDK
inline float invSqrt(float x)
{
float xhalf = 0.5f * x;
int i = *(int*)&x; // get bits for floating value
i = 0x5f3759df - (i>>1); // gives initial guess
x = *(float*)&i; // convert bits back to float
x = x * (1.5f - xhalf*x*x); // Newton step
return x;
}

///////////////////////////////////////////////////////////////////////////////
// inline functions for Vector2
///////////////////////////////////////////////////////////////////////////////
inline Vector2 Vector2::operator-() const {
return Vector2(-x, -y);
}

inline Vector2 Vector2::operator+(const Vector2& rhs) const {


return Vector2(x+rhs.x, y+rhs.y);
}

inline Vector2 Vector2::operator-(const Vector2& rhs) const {


return Vector2(x-rhs.x, y-rhs.y);
}

inline Vector2& Vector2::operator+=(const Vector2& rhs) {


x += rhs.x; y += rhs.y; return *this;
}

inline Vector2& Vector2::operator-=(const Vector2& rhs) {


x -= rhs.x; y -= rhs.y; return *this;
}

inline Vector2 Vector2::operator*(const float a) const {


return Vector2(x*a, y*a);
}

inline Vector2 Vector2::operator*(const Vector2& rhs) const {


return Vector2(x*rhs.x, y*rhs.y);
}

inline Vector2& Vector2::operator*=(const float a) {


x *= a; y *= a; return *this;
}

inline Vector2& Vector2::operator*=(const Vector2& rhs) {


x *= rhs.x; y *= rhs.y; return *this;
}

inline Vector2 Vector2::operator/(const float a) const {


return Vector2(x/a, y/a);
}

inline Vector2& Vector2::operator/=(const float a) {


x /= a; y /= a; return *this;
}

inline bool Vector2::operator==(const Vector2& rhs) const {


return (x == rhs.x) && (y == rhs.y);
}

inline bool Vector2::operator!=(const Vector2& rhs) const {


return (x != rhs.x) || (y != rhs.y);
}

inline bool Vector2::operator<(const Vector2& rhs) const {


if(x < rhs.x) return true;
if(x > rhs.x) return false;
if(y < rhs.y) return true;
if(y > rhs.y) return false;
return false;
}

inline float Vector2::operator[](int index) const {


return (&x)[index];

KhoaCNTT – Trường ĐHBK 14


}

inline float& Vector2::operator[](int index) {


return (&x)[index];
}

inline void Vector2::set(float x, float y) {


this->x = x; this->y = y;
}

inline float Vector2::length() const {


return sqrtf(x*x + y*y);
}

inline float Vector2::distance(const Vector2& vec) const {


return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y));
}

inline Vector2& Vector2::normalize() {


//@@const float EPSILON = 0.000001f;
float xxyy = x*x + y*y;
//@@if(xxyy < EPSILON)
//@@ return *this;

//float invLength = invSqrt(xxyy);


float invLength = 1.0f / sqrtf(xxyy);
x *= invLength;
y *= invLength;
return *this;
}

inline float Vector2::dot(const Vector2& rhs) const {


return (x*rhs.x + y*rhs.y);
}

inline bool Vector2::equal(const Vector2& rhs, float epsilon) const {


return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon;
}

inline Vector2 operator*(const float a, const Vector2 vec) {


return Vector2(a*vec.x, a*vec.y);
}

inline std::ostream& operator<<(std::ostream& os, const Vector2& vec) {


os << "(" << vec.x << ", " << vec.y << ")";
return os;
}
// END OF VECTOR2 /////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// inline functions for Vector3
///////////////////////////////////////////////////////////////////////////////
inline Vector3 Vector3::operator-() const {
return Vector3(-x, -y, -z);
}

inline Vector3 Vector3::operator+(const Vector3& rhs) const {


return Vector3(x+rhs.x, y+rhs.y, z+rhs.z);
}

inline Vector3 Vector3::operator-(const Vector3& rhs) const {


return Vector3(x-rhs.x, y-rhs.y, z-rhs.z);
}

inline Vector3& Vector3::operator+=(const Vector3& rhs) {


x += rhs.x; y += rhs.y; z += rhs.z; return *this;
}

inline Vector3& Vector3::operator-=(const Vector3& rhs) {


x -= rhs.x; y -= rhs.y; z -= rhs.z; return *this;
}

inline Vector3 Vector3::operator*(const float a) const {


return Vector3(x*a, y*a, z*a);
}

inline Vector3 Vector3::operator*(const Vector3& rhs) const {

KhoaCNTT – Trường ĐHBK 15


return Vector3(x*rhs.x, y*rhs.y, z*rhs.z);
}

inline Vector3& Vector3::operator*=(const float a) {


x *= a; y *= a; z *= a; return *this;
}

inline Vector3& Vector3::operator*=(const Vector3& rhs) {


x *= rhs.x; y *= rhs.y; z *= rhs.z; return *this;
}

inline Vector3 Vector3::operator/(const float a) const {


return Vector3(x/a, y/a, z/a);
}

inline Vector3& Vector3::operator/=(const float a) {


x /= a; y /= a; z /= a; return *this;
}

inline bool Vector3::operator==(const Vector3& rhs) const {


return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
}

inline bool Vector3::operator!=(const Vector3& rhs) const {


return (x != rhs.x) || (y != rhs.y) || (z != rhs.z);
}

inline bool Vector3::operator<(const Vector3& rhs) const {


if(x < rhs.x) return true;
if(x > rhs.x) return false;
if(y < rhs.y) return true;
if(y > rhs.y) return false;
if(z < rhs.z) return true;
if(z > rhs.z) return false;
return false;
}

inline float Vector3::operator[](int index) const {


return (&x)[index];
}

inline float& Vector3::operator[](int index) {


return (&x)[index];
}

inline void Vector3::set(float x, float y, float z) {


this->x = x; this->y = y; this->z = z;
}

inline float Vector3::length() const {


return sqrtf(x*x + y*y + z*z);
}

inline float Vector3::distance(const Vector3& vec) const {


return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y) + (vec.z-z)*(vec.z-z));
}

inline Vector3& Vector3::normalize() {


//@@const float EPSILON = 0.000001f;
float xxyyzz = x*x + y*y + z*z;
//@@if(xxyyzz < EPSILON)
//@@ return *this; // do nothing if it is ~zero vector

//float invLength = invSqrt(xxyyzz);


float invLength = 1.0f / sqrtf(xxyyzz);
x *= invLength;
y *= invLength;
z *= invLength;
return *this;
}

inline float Vector3::dot(const Vector3& rhs) const {


return (x*rhs.x + y*rhs.y + z*rhs.z);
}

inline Vector3 Vector3::cross(const Vector3& rhs) const {


return Vector3(y*rhs.z - z*rhs.y, z*rhs.x - x*rhs.z, x*rhs.y - y*rhs.x);
}

inline bool Vector3::equal(const Vector3& rhs, float epsilon) const {

KhoaCNTT – Trường ĐHBK 16


return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon && fabs(z - rhs.z) <
epsilon;
}

inline Vector3 operator*(const float a, const Vector3 vec) {


return Vector3(a*vec.x, a*vec.y, a*vec.z);
}

inline std::ostream& operator<<(std::ostream& os, const Vector3& vec) {


os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ")";
return os;
}
// END OF VECTOR3 /////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// inline functions for Vector4
///////////////////////////////////////////////////////////////////////////////
inline Vector4 Vector4::operator-() const {
return Vector4(-x, -y, -z, -w);
}

inline Vector4 Vector4::operator+(const Vector4& rhs) const {


return Vector4(x+rhs.x, y+rhs.y, z+rhs.z, w+rhs.w);
}

inline Vector4 Vector4::operator-(const Vector4& rhs) const {


return Vector4(x-rhs.x, y-rhs.y, z-rhs.z, w-rhs.w);
}

inline Vector4& Vector4::operator+=(const Vector4& rhs) {


x += rhs.x; y += rhs.y; z += rhs.z; w += rhs.w; return *this;
}

inline Vector4& Vector4::operator-=(const Vector4& rhs) {


x -= rhs.x; y -= rhs.y; z -= rhs.z; w -= rhs.w; return *this;
}

inline Vector4 Vector4::operator*(const float a) const {


return Vector4(x*a, y*a, z*a, w*a);
}

inline Vector4 Vector4::operator*(const Vector4& rhs) const {


return Vector4(x*rhs.x, y*rhs.y, z*rhs.z, w*rhs.w);
}

inline Vector4& Vector4::operator*=(const float a) {


x *= a; y *= a; z *= a; w *= a; return *this;
}

inline Vector4& Vector4::operator*=(const Vector4& rhs) {


x *= rhs.x; y *= rhs.y; z *= rhs.z; w *= rhs.w; return *this;
}

inline Vector4 Vector4::operator/(const float a) const {


return Vector4(x/a, y/a, z/a, w/a);
}

inline Vector4& Vector4::operator/=(const float a) {


x /= a; y /= a; z /= a; w /= a; return *this;
}

inline bool Vector4::operator==(const Vector4& rhs) const {


return (x == rhs.x) && (y == rhs.y) && (z == rhs.z) && (w == rhs.w);
}

inline bool Vector4::operator!=(const Vector4& rhs) const {


return (x != rhs.x) || (y != rhs.y) || (z != rhs.z) || (w != rhs.w);
}

inline bool Vector4::operator<(const Vector4& rhs) const {


if(x < rhs.x) return true;
if(x > rhs.x) return false;
if(y < rhs.y) return true;
if(y > rhs.y) return false;
if(z < rhs.z) return true;
if(z > rhs.z) return false;
if(w < rhs.w) return true;
if(w > rhs.w) return false;

KhoaCNTT – Trường ĐHBK 17


return false;
}

inline float Vector4::operator[](int index) const {


return (&x)[index];
}

inline float& Vector4::operator[](int index) {


return (&x)[index];
}

inline void Vector4::set(float x, float y, float z, float w) {


this->x = x; this->y = y; this->z = z; this->w = w;
}

inline float Vector4::length() const {


return sqrtf(x*x + y*y + z*z + w*w);
}

inline float Vector4::distance(const Vector4& vec) const {


return sqrtf((vec.x-x)*(vec.x-x) + (vec.y-y)*(vec.y-y) + (vec.z-z)*(vec.z-z) + (vec.w-
w)*(vec.w-w));
}

inline Vector4& Vector4::normalize() {


//NOTE: leave w-component untouched
//@@const float EPSILON = 0.000001f;
float xxyyzz = x*x + y*y + z*z;
//@@if(xxyyzz < EPSILON)
//@@ return *this; // do nothing if it is zero vector

//float invLength = invSqrt(xxyyzz);


float invLength = 1.0f / sqrtf(xxyyzz);
x *= invLength;
y *= invLength;
z *= invLength;
return *this;
}

inline float Vector4::dot(const Vector4& rhs) const {


return (x*rhs.x + y*rhs.y + z*rhs.z + w*rhs.w);
}

inline bool Vector4::equal(const Vector4& rhs, float epsilon) const {


return fabs(x - rhs.x) < epsilon && fabs(y - rhs.y) < epsilon &&
fabs(z - rhs.z) < epsilon && fabs(w - rhs.w) < epsilon;
}

inline Vector4 operator*(const float a, const Vector4 vec) {


return Vector4(a*vec.x, a*vec.y, a*vec.z, a*vec.w);
}

inline std::ostream& operator<<(std::ostream& os, const Vector4& vec) {


os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ", " << vec.w << ")";
return os;
}
// END OF VECTOR4 /////////////////////////////////////////////////////////////

#endif

2.2 Matrices.h
///////////////////////////////////////////////////////////////////////////////
// Matrice.h
// =========
// NxN Matrix Math classes
//
// All matrices are row major. (OpenGL uses column-major matrix)
// | 0 1 | | 0 1 2 | | 0 1 2 3 |
// | 2 3 | | 3 4 5 | | 4 5 6 7 |
// | 6 7 8 | | 8 9 10 11 |
// | 12 13 14 15 |
///////////////////////////////////////////////////////////////////////////////

#ifndef MATH_MATRICES_H
#define MATH_MATRICES_H

#include "Vectors.h"

KhoaCNTT – Trường ĐHBK 18


///////////////////////////////////////////////////////////////////////////
// 2x2 matrix
///////////////////////////////////////////////////////////////////////////
class Matrix2
{
public:
// constructors
Matrix2(); // init with identity
Matrix2(const float src[4]);
Matrix2(float xx, float xy, float yx, float yy);

void set(const float src[4]);


void set(float xx, float xy, float yx, float yy);
void setRow(int index, const float row[2]);
void setRow(int index, const Vector2& v);
void setColumn(int index, const float col[2]);
void setColumn(int index, const Vector2& v);

const float* get() const;


float getDeterminant();

Matrix2& identity();
Matrix2& transpose(); // transpose itself and return
reference
Matrix2& invert();

// operators
Matrix2 operator+(const Matrix2& rhs) const; // add rhs
Matrix2 operator-(const Matrix2& rhs) const; // subtract rhs
Matrix2& operator+=(const Matrix2& rhs); // add rhs and update this object
Matrix2& operator-=(const Matrix2& rhs); // subtract rhs and update this object
Vector2 operator*(const Vector2& rhs) const; // multiplication: v' = M * v
Matrix2 operator*(const Matrix2& rhs) const; // multiplication: M3 = M1 * M2
Matrix2& operator*=(const Matrix2& rhs); // multiplication: M1' = M1 * M2
bool operator==(const Matrix2& rhs) const; // exact compare, no epsilon
bool operator!=(const Matrix2& rhs) const; // exact compare, no epsilon
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]

friend Matrix2 operator-(const Matrix2& m); // unary operator (-)


friend Matrix2 operator*(float scalar, const Matrix2& m); // pre-multiplication
friend Vector2 operator*(const Vector2& vec, const Matrix2& m); // pre-multiplication
friend std::ostream& operator<<(std::ostream& os, const Matrix2& m);

protected:

private:
float m[4];

};

///////////////////////////////////////////////////////////////////////////
// 3x3 matrix
///////////////////////////////////////////////////////////////////////////
class Matrix3
{
public:
// constructors
Matrix3(); // init with identity
Matrix3(const float src[9]);
Matrix3(float xx, float xy, float xz,
float yx, float yy, float yz,
float zx, float zy, float zz);

void set(const float src[9]);


void set(float xx, float xy, float xz,
float yx, float yy, float yz,
float zx, float zy, float zz);
void setRow(int index, const float row[3]);
void setRow(int index, const Vector3& v);
void setColumn(int index, const float col[3]);
void setColumn(int index, const Vector3& v);

const float* get() const;


float getDeterminant();

Matrix3& identity();
Matrix3& transpose(); // transpose itself and return
reference
Matrix3& invert();

KhoaCNTT – Trường ĐHBK 19


// operators
Matrix3 operator+(const Matrix3& rhs) const; // add rhs
Matrix3 operator-(const Matrix3& rhs) const; // subtract rhs
Matrix3& operator+=(const Matrix3& rhs); // add rhs and update this object
Matrix3& operator-=(const Matrix3& rhs); // subtract rhs and update this object
Vector3 operator*(const Vector3& rhs) const; // multiplication: v' = M * v
Matrix3 operator*(const Matrix3& rhs) const; // multiplication: M3 = M1 * M2
Matrix3& operator*=(const Matrix3& rhs); // multiplication: M1' = M1 * M2
bool operator==(const Matrix3& rhs) const; // exact compare, no epsilon
bool operator!=(const Matrix3& rhs) const; // exact compare, no epsilon
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]

friend Matrix3 operator-(const Matrix3& m); // unary operator (-)


friend Matrix3 operator*(float scalar, const Matrix3& m); // pre-multiplication
friend Vector3 operator*(const Vector3& vec, const Matrix3& m); // pre-multiplication
friend std::ostream& operator<<(std::ostream& os, const Matrix3& m);

protected:

private:
float m[9];

};

///////////////////////////////////////////////////////////////////////////
// 4x4 matrix
///////////////////////////////////////////////////////////////////////////
class Matrix4
{
public:
// constructors
Matrix4(); // init with identity
Matrix4(const float src[16]);
Matrix4(float xx, float xy, float xz, float xw,
float yx, float yy, float yz, float yw,
float zx, float zy, float zz, float zw,
float wx, float wy, float wz, float ww);

void set(const float src[16]);


void set(float xx, float xy, float xz, float xw,
float yx, float yy, float yz, float yw,
float zx, float zy, float zz, float zw,
float wx, float wy, float wz, float ww);
void setRow(int index, const float row[4]);
void setRow(int index, const Vector4& v);
void setRow(int index, const Vector3& v);
void setColumn(int index, const float col[4]);
void setColumn(int index, const Vector4& v);
void setColumn(int index, const Vector3& v);

const float* get() const;


const float* getTranspose(); // return transposed matrix
float getDeterminant();

Matrix4& identity();
Matrix4& transpose(); // transpose itself and return
reference
Matrix4& invert(); // check best inverse method before
inverse
Matrix4& invertEuclidean(); // inverse of Euclidean transform
matrix
Matrix4& invertAffine(); // inverse of affine transform matrix
Matrix4& invertProjective(); // inverse of projective matrix using
partitioning
Matrix4& invertGeneral(); // inverse of generic matrix

// transform matrix
Matrix4& translate(float x, float y, float z); // translation by (x,y,z)
Matrix4& translate(const Vector3& v); //
Matrix4& rotate(float angle, const Vector3& axis); // rotate angle(degree) along the
given axix
Matrix4& rotate(float angle, float x, float y, float z);
Matrix4& rotateX(float angle); // rotate on X-axis with degree
Matrix4& rotateY(float angle); // rotate on Y-axis with degree
Matrix4& rotateZ(float angle); // rotate on Z-axis with degree
Matrix4& scale(float scale); // uniform scale
Matrix4& scale(float sx, float sy, float sz); // scale by (sx, sy, sz) on each axis

KhoaCNTT – Trường ĐHBK 20


// operators
Matrix4 operator+(const Matrix4& rhs) const; // add rhs
Matrix4 operator-(const Matrix4& rhs) const; // subtract rhs
Matrix4& operator+=(const Matrix4& rhs); // add rhs and update this object
Matrix4& operator-=(const Matrix4& rhs); // subtract rhs and update this object
Vector4 operator*(const Vector4& rhs) const; // multiplication: v' = M * v
Vector3 operator*(const Vector3& rhs) const; // multiplication: v' = M * v
Matrix4 operator*(const Matrix4& rhs) const; // multiplication: M3 = M1 * M2
Matrix4& operator*=(const Matrix4& rhs); // multiplication: M1' = M1 * M2
bool operator==(const Matrix4& rhs) const; // exact compare, no epsilon
bool operator!=(const Matrix4& rhs) const; // exact compare, no epsilon
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]

friend Matrix4 operator-(const Matrix4& m); // unary operator (-)


friend Matrix4 operator*(float scalar, const Matrix4& m); // pre-multiplication
friend Vector3 operator*(const Vector3& vec, const Matrix4& m); // pre-multiplication
friend Vector4 operator*(const Vector4& vec, const Matrix4& m); // pre-multiplication
friend std::ostream& operator<<(std::ostream& os, const Matrix4& m);

protected:

private:
float getCofactor(float m0, float m1, float m2,
float m3, float m4, float m5,
float m6, float m7, float m8);

float m[16];
float tm[16]; // transpose m

};

///////////////////////////////////////////////////////////////////////////
// inline functions for Matrix2
///////////////////////////////////////////////////////////////////////////
inline Matrix2::Matrix2()
{
// initially identity matrix
identity();
}

inline Matrix2::Matrix2(const float src[4])


{
set(src);
}

inline Matrix2::Matrix2(float xx, float xy, float yx, float yy)


{
set(xx, xy, yx, yy);
}

inline void Matrix2::set(const float src[4])


{
m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
}

inline void Matrix2::set(float xx, float xy, float yx, float yy)
{
m[0]= xx; m[1] = xy; m[2] = yx; m[3]= yy;
}

inline void Matrix2::setRow(int index, const float row[2])


{
m[index*2] = row[0]; m[index*2 + 1] = row[1];
}

inline void Matrix2::setRow(int index, const Vector2& v)


{
m[index*2] = v.x; m[index*2 + 1] = v.y;
}

inline void Matrix2::setColumn(int index, const float col[2])


{
m[index] = col[0]; m[index + 2] = col[1];
}

inline void Matrix2::setColumn(int index, const Vector2& v)


{
m[index] = v.x; m[index + 2] = v.y;

KhoaCNTT – Trường ĐHBK 21


}

inline const float* Matrix2::get() const


{
return m;
}

inline Matrix2& Matrix2::identity()


{
m[0] = m[3] = 1.0f;
m[1] = m[2] = 0.0f;
return *this;
}

inline Matrix2 Matrix2::operator+(const Matrix2& rhs) const


{
return Matrix2(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2], m[3]+rhs[3]);
}

inline Matrix2 Matrix2::operator-(const Matrix2& rhs) const


{
return Matrix2(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2], m[3]-rhs[3]);
}

inline Matrix2& Matrix2::operator+=(const Matrix2& rhs)


{
m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2]; m[3] += rhs[3];
return *this;
}

inline Matrix2& Matrix2::operator-=(const Matrix2& rhs)


{
m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2]; m[3] -= rhs[3];
return *this;
}

inline Vector2 Matrix2::operator*(const Vector2& rhs) const


{
return Vector2(m[0]*rhs.x + m[1]*rhs.y, m[2]*rhs.x + m[3]*rhs.y);
}

inline Matrix2 Matrix2::operator*(const Matrix2& rhs) const


{
return Matrix2(m[0]*rhs[0] + m[1]*rhs[2], m[0]*rhs[1] + m[1]*rhs[3],
m[2]*rhs[0] + m[3]*rhs[2], m[2]*rhs[1] + m[3]*rhs[3]);
}

inline Matrix2& Matrix2::operator*=(const Matrix2& rhs)


{
*this = *this * rhs;
return *this;
}

inline bool Matrix2::operator==(const Matrix2& rhs) const


{
return (m[0] == rhs[0]) && (m[1] == rhs[1]) && (m[2] == rhs[2]) && (m[3] == rhs[3]);
}

inline bool Matrix2::operator!=(const Matrix2& rhs) const


{
return (m[0] != rhs[0]) || (m[1] != rhs[1]) || (m[2] != rhs[2]) || (m[3] != rhs[3]);
}

inline float Matrix2::operator[](int index) const


{
return m[index];
}

inline float& Matrix2::operator[](int index)


{
return m[index];
}

inline Matrix2 operator-(const Matrix2& rhs)


{
return Matrix2(-rhs[0], -rhs[1], -rhs[2], -rhs[3]);
}

inline Matrix2 operator*(float s, const Matrix2& rhs)


{

KhoaCNTT – Trường ĐHBK 22


return Matrix2(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3]);
}

inline Vector2 operator*(const Vector2& v, const Matrix2& rhs)


{
return Vector2(v.x*rhs[0] + v.y*rhs[2], v.x*rhs[1] + v.y*rhs[3]);
}

inline std::ostream& operator<<(std::ostream& os, const Matrix2& m)


{
os << "(" << m[0] << ",\t" << m[1] << ")\n"
<< "(" << m[2] << ",\t" << m[3] << ")\n";
return os;
}
// END OF MATRIX2 INLINE //////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// inline functions for Matrix3
///////////////////////////////////////////////////////////////////////////
inline Matrix3::Matrix3()
{
// initially identity matrix
identity();
}

inline Matrix3::Matrix3(const float src[9])


{
set(src);
}

inline Matrix3::Matrix3(float xx, float xy, float xz,


float yx, float yy, float yz,
float zx, float zy, float zz)
{
set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
}

inline void Matrix3::set(const float src[9])


{
m[0] = src[0]; m[1] = src[1]; m[2] = src[2];
m[3] = src[3]; m[4] = src[4]; m[5] = src[5];
m[6] = src[6]; m[7] = src[7]; m[8] = src[8];
}

inline void Matrix3::set(float xx, float xy, float xz,


float yx, float yy, float yz,
float zx, float zy, float zz)
{
m[0] = xx; m[1] = xy; m[2] = xz;
m[3] = yx; m[4] = yy; m[5] = yz;
m[6] = zx; m[7] = zy; m[8] = zz;
}

inline void Matrix3::setRow(int index, const float row[3])


{
m[index*3] = row[0]; m[index*3 + 1] = row[1]; m[index*3 + 2] = row[2];
}

inline void Matrix3::setRow(int index, const Vector3& v)


{
m[index*3] = v.x; m[index*3 + 1] = v.y; m[index*3 + 2] = v.z;
}

inline void Matrix3::setColumn(int index, const float col[3])


{
m[index] = col[0]; m[index + 3] = col[1]; m[index + 6] = col[2];
}

inline void Matrix3::setColumn(int index, const Vector3& v)


{
m[index] = v.x; m[index + 3] = v.y; m[index + 6] = v.z;
}

inline const float* Matrix3::get() const


{
return m;
}

inline Matrix3& Matrix3::identity()

KhoaCNTT – Trường ĐHBK 23


{
m[0] = m[4] = m[8] = 1.0f;
m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0.0f;
return *this;
}

inline Matrix3 Matrix3::operator+(const Matrix3& rhs) const


{
return Matrix3(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2],
m[3]+rhs[3], m[4]+rhs[4], m[5]+rhs[5],
m[6]+rhs[6], m[7]+rhs[7], m[8]+rhs[8]);
}

inline Matrix3 Matrix3::operator-(const Matrix3& rhs) const


{
return Matrix3(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2],
m[3]-rhs[3], m[4]-rhs[4], m[5]-rhs[5],
m[6]-rhs[6], m[7]-rhs[7], m[8]-rhs[8]);
}

inline Matrix3& Matrix3::operator+=(const Matrix3& rhs)


{
m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2];
m[3] += rhs[3]; m[4] += rhs[4]; m[5] += rhs[5];
m[6] += rhs[6]; m[7] += rhs[7]; m[8] += rhs[8];
return *this;
}

inline Matrix3& Matrix3::operator-=(const Matrix3& rhs)


{
m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2];
m[3] -= rhs[3]; m[4] -= rhs[4]; m[5] -= rhs[5];
m[6] -= rhs[6]; m[7] -= rhs[7]; m[8] -= rhs[8];
return *this;
}

inline Vector3 Matrix3::operator*(const Vector3& rhs) const


{
return Vector3(m[0]*rhs.x + m[1]*rhs.y + m[2]*rhs.z,
m[3]*rhs.x + m[4]*rhs.y + m[5]*rhs.z,
m[6]*rhs.x + m[7]*rhs.y + m[8]*rhs.z);
}

inline Matrix3 Matrix3::operator*(const Matrix3& rhs) const


{
return Matrix3(m[0]*rhs[0] + m[1]*rhs[3] + m[2]*rhs[6], m[0]*rhs[1] + m[1]*rhs[4] +
m[2]*rhs[7], m[0]*rhs[2] + m[1]*rhs[5] + m[2]*rhs[8],
m[3]*rhs[0] + m[4]*rhs[3] + m[5]*rhs[6], m[3]*rhs[1] + m[4]*rhs[4] +
m[5]*rhs[7], m[3]*rhs[2] + m[4]*rhs[5] + m[5]*rhs[8],
m[6]*rhs[0] + m[7]*rhs[3] + m[8]*rhs[6], m[6]*rhs[1] + m[7]*rhs[4] +
m[8]*rhs[7], m[6]*rhs[2] + m[7]*rhs[5] + m[8]*rhs[8]);
}

inline Matrix3& Matrix3::operator*=(const Matrix3& rhs)


{
*this = *this * rhs;
return *this;
}

inline bool Matrix3::operator==(const Matrix3& rhs) const


{
return (m[0] == rhs[0]) && (m[1] == rhs[1]) && (m[2] == rhs[2]) &&
(m[3] == rhs[3]) && (m[4] == rhs[4]) && (m[5] == rhs[5]) &&
(m[6] == rhs[6]) && (m[7] == rhs[7]) && (m[8] == rhs[8]);
}

inline bool Matrix3::operator!=(const Matrix3& rhs) const


{
return (m[0] != rhs[0]) || (m[1] != rhs[1]) || (m[2] != rhs[2]) ||
(m[3] != rhs[3]) || (m[4] != rhs[4]) || (m[5] != rhs[5]) ||
(m[6] != rhs[6]) || (m[7] != rhs[7]) || (m[8] != rhs[8]);
}

inline float Matrix3::operator[](int index) const


{
return m[index];
}

inline float& Matrix3::operator[](int index)


{

KhoaCNTT – Trường ĐHBK 24


return m[index];
}

inline Matrix3 operator-(const Matrix3& rhs)


{
return Matrix3(-rhs[0], -rhs[1], -rhs[2], -rhs[3], -rhs[4], -rhs[5], -rhs[6], -rhs[7], -
rhs[8]);
}

inline Matrix3 operator*(float s, const Matrix3& rhs)


{
return Matrix3(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3], s*rhs[4], s*rhs[5], s*rhs[6],
s*rhs[7], s*rhs[8]);
}

inline Vector3 operator*(const Vector3& v, const Matrix3& m)


{
return Vector3(v.x*m[0] + v.y*m[3] + v.z*m[6], v.x*m[1] + v.y*m[4] + v.z*m[7], v.x*m[2]
+ v.y*m[5] + v.z*m[8]);
}

inline std::ostream& operator<<(std::ostream& os, const Matrix3& m)


{
os << "(" << m[0] << ",\t" << m[1] << ",\t" << m[2] << ")\n"
<< "(" << m[3] << ",\t" << m[4] << ",\t" << m[5] << ")\n"
<< "(" << m[6] << ",\t" << m[7] << ",\t" << m[8] << ")\n";
return os;
}
// END OF MATRIX3 INLINE //////////////////////////////////////////////////////

// inline functions for Matrix4


inline Matrix4::Matrix4()
{
// initially identity matrix
identity();
}

inline Matrix4::Matrix4(const float src[16])


{
set(src);
}

inline Matrix4::Matrix4(float xx, float xy, float xz, float xw,


float yx, float yy, float yz, float yw,
float zx, float zy, float zz, float zw,
float wx, float wy, float wz, float ww)
{
set(xx, xy, xz, xw, yx, yy, yz, yw, zx, zy, zz, zw, wx, wy, wz, ww);
}

inline void Matrix4::set(const float src[16])


{
m[0] = src[0]; m[1] = src[1]; m[2] = src[2]; m[3] = src[3];
m[4] = src[4]; m[5] = src[5]; m[6] = src[6]; m[7] = src[7];
m[8] = src[8]; m[9] = src[9]; m[10]= src[10]; m[11]= src[11];
m[12]= src[12]; m[13]= src[13]; m[14]= src[14]; m[15]= src[15];
}

inline void Matrix4::set(float xx, float xy, float xz, float xw,
float yx, float yy, float yz, float yw,
float zx, float zy, float zz, float zw,
float wx, float wy, float wz, float ww)
{
m[0] = xx; m[1] = xy; m[2] = xz; m[3] = xw;
m[4] = yx; m[5] = yy; m[6] = yz; m[7] = yw;
m[8] = zx; m[9] = zy; m[10]= zz; m[11]= zw;
m[12]= wx; m[13]= wy; m[14]= wz; m[15]= ww;
}

inline void Matrix4::setRow(int index, const float row[4])


{
m[index*4] = row[0]; m[index*4 + 1] = row[1]; m[index*4 + 2] = row[2]; m[index*4 + 3] =
row[3];
}

inline void Matrix4::setRow(int index, const Vector4& v)


{
m[index*4] = v.x; m[index*4 + 1] = v.y; m[index*4 + 2] = v.z; m[index*4 + 3] = v.w;
}

KhoaCNTT – Trường ĐHBK 25


inline void Matrix4::setRow(int index, const Vector3& v)
{
m[index*4] = v.x; m[index*4 + 1] = v.y; m[index*4 + 2] = v.z;
}

inline void Matrix4::setColumn(int index, const float col[4])


{
m[index] = col[0]; m[index + 4] = col[1]; m[index + 8] = col[2]; m[index + 12] =
col[3];
}

inline void Matrix4::setColumn(int index, const Vector4& v)


{
m[index] = v.x; m[index + 4] = v.y; m[index + 8] = v.z; m[index + 12] = v.w;
}

inline void Matrix4::setColumn(int index, const Vector3& v)


{
m[index] = v.x; m[index + 4] = v.y; m[index + 8] = v.z;
}

inline const float* Matrix4::get() const


{
return m;
}

inline const float* Matrix4::getTranspose()


{
tm[0] = m[0]; tm[1] = m[4]; tm[2] = m[8]; tm[3] = m[12];
tm[4] = m[1]; tm[5] = m[5]; tm[6] = m[9]; tm[7] = m[13];
tm[8] = m[2]; tm[9] = m[6]; tm[10]= m[10]; tm[11]= m[14];
tm[12]= m[3]; tm[13]= m[7]; tm[14]= m[11]; tm[15]= m[15];
return tm;
}

inline Matrix4& Matrix4::identity()


{
m[0] = m[5] = m[10] = m[15] = 1.0f;
m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[11] = m[12] = m[13] = m[14] =
0.0f;
return *this;
}

inline Matrix4 Matrix4::operator+(const Matrix4& rhs) const


{
return Matrix4(m[0]+rhs[0], m[1]+rhs[1], m[2]+rhs[2], m[3]+rhs[3],
m[4]+rhs[4], m[5]+rhs[5], m[6]+rhs[6], m[7]+rhs[7],
m[8]+rhs[8], m[9]+rhs[9], m[10]+rhs[10], m[11]+rhs[11],
m[12]+rhs[12], m[13]+rhs[13], m[14]+rhs[14], m[15]+rhs[15]);
}

inline Matrix4 Matrix4::operator-(const Matrix4& rhs) const


{
return Matrix4(m[0]-rhs[0], m[1]-rhs[1], m[2]-rhs[2], m[3]-rhs[3],
m[4]-rhs[4], m[5]-rhs[5], m[6]-rhs[6], m[7]-rhs[7],
m[8]-rhs[8], m[9]-rhs[9], m[10]-rhs[10], m[11]-rhs[11],
m[12]-rhs[12], m[13]-rhs[13], m[14]-rhs[14], m[15]-rhs[15]);
}

inline Matrix4& Matrix4::operator+=(const Matrix4& rhs)


{
m[0] += rhs[0]; m[1] += rhs[1]; m[2] += rhs[2]; m[3] += rhs[3];
m[4] += rhs[4]; m[5] += rhs[5]; m[6] += rhs[6]; m[7] += rhs[7];
m[8] += rhs[8]; m[9] += rhs[9]; m[10] += rhs[10]; m[11] += rhs[11];
m[12] += rhs[12]; m[13] += rhs[13]; m[14] += rhs[14]; m[15] += rhs[15];
return *this;
}

inline Matrix4& Matrix4::operator-=(const Matrix4& rhs)


{
m[0] -= rhs[0]; m[1] -= rhs[1]; m[2] -= rhs[2]; m[3] -= rhs[3];
m[4] -= rhs[4]; m[5] -= rhs[5]; m[6] -= rhs[6]; m[7] -= rhs[7];
m[8] -= rhs[8]; m[9] -= rhs[9]; m[10] -= rhs[10]; m[11] -= rhs[11];
m[12] -= rhs[12]; m[13] -= rhs[13]; m[14] -= rhs[14]; m[15] -= rhs[15];
return *this;
}

inline Vector4 Matrix4::operator*(const Vector4& rhs) const


{
return Vector4(m[0]*rhs.x + m[1]*rhs.y + m[2]*rhs.z + m[3]*rhs.w,

KhoaCNTT – Trường ĐHBK 26


m[4]*rhs.x + m[5]*rhs.y + m[6]*rhs.z + m[7]*rhs.w,
m[8]*rhs.x + m[9]*rhs.y + m[10]*rhs.z + m[11]*rhs.w,
m[12]*rhs.x + m[13]*rhs.y + m[14]*rhs.z + m[15]*rhs.w);
}

inline Vector3 Matrix4::operator*(const Vector3& rhs) const


{
return Vector3(m[0]*rhs.x + m[1]*rhs.y + m[2]*rhs.z,
m[4]*rhs.x + m[5]*rhs.y + m[6]*rhs.z,
m[8]*rhs.x + m[9]*rhs.y + m[10]*rhs.z);
}

inline Matrix4 Matrix4::operator*(const Matrix4& n) const


{
return Matrix4(m[0]*n[0] + m[1]*n[4] + m[2]*n[8] + m[3]*n[12], m[0]*n[1] + m[1]*n[5]
+ m[2]*n[9] + m[3]*n[13], m[0]*n[2] + m[1]*n[6] + m[2]*n[10] + m[3]*n[14], m[0]*n[3]
+ m[1]*n[7] + m[2]*n[11] + m[3]*n[15],
m[4]*n[0] + m[5]*n[4] + m[6]*n[8] + m[7]*n[12], m[4]*n[1] + m[5]*n[5]
+ m[6]*n[9] + m[7]*n[13], m[4]*n[2] + m[5]*n[6] + m[6]*n[10] + m[7]*n[14], m[4]*n[3]
+ m[5]*n[7] + m[6]*n[11] + m[7]*n[15],
m[8]*n[0] + m[9]*n[4] + m[10]*n[8] + m[11]*n[12], m[8]*n[1] + m[9]*n[5]
+ m[10]*n[9] + m[11]*n[13], m[8]*n[2] + m[9]*n[6] + m[10]*n[10] + m[11]*n[14], m[8]*n[3]
+ m[9]*n[7] + m[10]*n[11] + m[11]*n[15],
m[12]*n[0] + m[13]*n[4] + m[14]*n[8] + m[15]*n[12], m[12]*n[1] +
m[13]*n[5] + m[14]*n[9] + m[15]*n[13], m[12]*n[2] + m[13]*n[6] + m[14]*n[10] + m[15]*n[14],
m[12]*n[3] + m[13]*n[7] + m[14]*n[11] + m[15]*n[15]);
}

inline Matrix4& Matrix4::operator*=(const Matrix4& rhs)


{
*this = *this * rhs;
return *this;
}

inline bool Matrix4::operator==(const Matrix4& n) const


{
return (m[0] == n[0]) && (m[1] == n[1]) && (m[2] == n[2]) && (m[3] == n[3]) &&
(m[4] == n[4]) && (m[5] == n[5]) && (m[6] == n[6]) && (m[7] == n[7]) &&
(m[8] == n[8]) && (m[9] == n[9]) && (m[10] == n[10]) && (m[11] == n[11]) &&
(m[12] == n[12]) && (m[13] == n[13]) && (m[14] == n[14]) && (m[15] == n[15]);
}

inline bool Matrix4::operator!=(const Matrix4& n) const


{
return (m[0] != n[0]) || (m[1] != n[1]) || (m[2] != n[2]) || (m[3] != n[3]) ||
(m[4] != n[4]) || (m[5] != n[5]) || (m[6] != n[6]) || (m[7] != n[7]) ||
(m[8] != n[8]) || (m[9] != n[9]) || (m[10] != n[10]) || (m[11] != n[11]) ||
(m[12] != n[12]) || (m[13] != n[13]) || (m[14] != n[14]) || (m[15] != n[15]);
}

inline float Matrix4::operator[](int index) const


{
return m[index];
}

inline float& Matrix4::operator[](int index)


{
return m[index];
}

inline Matrix4 operator-(const Matrix4& rhs)


{
return Matrix4(-rhs[0], -rhs[1], -rhs[2], -rhs[3], -rhs[4], -rhs[5], -rhs[6], -rhs[7], -
rhs[8], -rhs[9], -rhs[10], -rhs[11], -rhs[12], -rhs[13], -rhs[14], -rhs[15]);
}

inline Matrix4 operator*(float s, const Matrix4& rhs)


{
return Matrix4(s*rhs[0], s*rhs[1], s*rhs[2], s*rhs[3], s*rhs[4], s*rhs[5], s*rhs[6],
s*rhs[7], s*rhs[8], s*rhs[9], s*rhs[10], s*rhs[11], s*rhs[12], s*rhs[13], s*rhs[14],
s*rhs[15]);
}

inline Vector4 operator*(const Vector4& v, const Matrix4& m)


{
return Vector4(v.x*m[0] + v.y*m[4] + v.z*m[8] + v.w*m[12], v.x*m[1] + v.y*m[5] + v.z*m[9]
+ v.w*m[13], v.x*m[2] + v.y*m[6] + v.z*m[10] + v.w*m[14], v.x*m[3] + v.y*m[7] + v.z*m[11] +
v.w*m[15]);
}

KhoaCNTT – Trường ĐHBK 27


inline Vector3 operator*(const Vector3& v, const Matrix4& m)
{
return Vector3(v.x*m[0] + v.y*m[4] + v.z*m[8], v.x*m[1] + v.y*m[5] + v.z*m[9], v.x*m[2]
+ v.y*m[6] + v.z*m[10]);
}

inline std::ostream& operator<<(std::ostream& os, const Matrix4& m)


{
os << "(" << m[0] << ",\t" << m[1] << ",\t" << m[2] << ",\t" << m[3] << ")\n"
<< "(" << m[4] << ",\t" << m[5] << ",\t" << m[6] << ",\t" << m[7] << ")\n"
<< "(" << m[8] << ",\t" << m[9] << ",\t" << m[10] << ",\t" << m[11] << ")\n"
<< "(" << m[12] << ",\t" << m[13] << ",\t" << m[14] << ",\t" << m[15] << ")\n";
return os;
}
// END OF MATRIX4 INLINE //////////////////////////////////////////////////////
#endif

2.3 main.cpp
///////////////////////////////////////////////////////////////////////////////
// matrix.cpp
// ==========
// Example of understanding OpenGL transform matrix(GL_MODELVIEW)
///////////////////////////////////////////////////////////////////////////////

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
//#include "Matrices.h"
#include "Vectors.h"

using std::stringstream;
using std::cout;
using std::endl;
using std::ends;

//==================================================

///////////////////////////////////////////////////////////////////////////////
// Matrice.cpp
// ===========
// NxN Matrix Math classes
//
// All matrices are row major. (OpenGL uses column-major matrix)
// | 0 1 | | 0 1 2 | | 0 1 2 3 |
// | 2 3 | | 3 4 5 | | 4 5 6 7 |
// | 6 7 8 | | 8 9 10 11 |
// | 12 13 14 15 |
//
///////////////////////////////////////////////////////////////////////////////

#include <cmath>
#include <algorithm>
#include "Matrices.h"

const float DEG2RAD = 3.141593f / 180;

///////////////////////////////////////////////////////////////////////////////
// return the determinant of 2x2 matrix
///////////////////////////////////////////////////////////////////////////////
float Matrix2::getDeterminant()
{
return m[0] * m[3] - m[1] * m[2];
}

///////////////////////////////////////////////////////////////////////////////
// inverse of 2x2 matrix
// If cannot find inverse, set identity matrix
///////////////////////////////////////////////////////////////////////////////
Matrix2& Matrix2::invert()
{

KhoaCNTT – Trường ĐHBK 28


float determinant = m[0] * m[3] - m[1] * m[2];
if(fabs(determinant) <= 0.00001f)
{
return identity();
}

float tmp = m[0]; // copy the first element


float invDeterminant = 1.0f / determinant;
m[0] = invDeterminant * m[3];
m[1] = -invDeterminant * m[1];
m[2] = -invDeterminant * m[2];
m[3] = invDeterminant * tmp;

return *this;
}

///////////////////////////////////////////////////////////////////////////////
// return determinant of 3x3 matrix
///////////////////////////////////////////////////////////////////////////////
float Matrix3::getDeterminant()
{
return m[0] * (m[4] * m[8] - m[5] * m[7]) -
m[1] * (m[3] * m[8] - m[5] * m[6]) +
m[2] * (m[3] * m[7] - m[4] * m[6]);
}

///////////////////////////////////////////////////////////////////////////////
// inverse 3x3 matrix
// If cannot find inverse, set identity matrix
///////////////////////////////////////////////////////////////////////////////
Matrix3& Matrix3::invert()
{
float determinant, invDeterminant;
float tmp[9];

tmp[0] = m[4] * m[8] - m[5] * m[7];


tmp[1] = m[2] * m[7] - m[1] * m[8];
tmp[2] = m[1] * m[5] - m[2] * m[4];
tmp[3] = m[5] * m[6] - m[3] * m[8];
tmp[4] = m[0] * m[8] - m[2] * m[6];
tmp[5] = m[2] * m[3] - m[0] * m[5];
tmp[6] = m[3] * m[7] - m[4] * m[6];
tmp[7] = m[1] * m[6] - m[0] * m[7];
tmp[8] = m[0] * m[4] - m[1] * m[3];

// check determinant if it is 0
determinant = m[0] * tmp[0] + m[1] * tmp[3] + m[2] * tmp[6];
if(fabs(determinant) <= 0.00001f)
{
return identity(); // cannot inverse, make it idenety matrix
}

// divide by the determinant


invDeterminant = 1.0f / determinant;
m[0] = invDeterminant * tmp[0];
m[1] = invDeterminant * tmp[1];
m[2] = invDeterminant * tmp[2];
m[3] = invDeterminant * tmp[3];
m[4] = invDeterminant * tmp[4];
m[5] = invDeterminant * tmp[5];
m[6] = invDeterminant * tmp[6];
m[7] = invDeterminant * tmp[7];
m[8] = invDeterminant * tmp[8];

return *this;
}

///////////////////////////////////////////////////////////////////////////////
// transpose 4x4 matrix
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::transpose()
{
std::swap(m[1], m[4]);
std::swap(m[2], m[8]);
std::swap(m[3], m[12]);
std::swap(m[6], m[9]);
std::swap(m[7], m[13]);
std::swap(m[11], m[14]);

return *this;

KhoaCNTT – Trường ĐHBK 29


}

///////////////////////////////////////////////////////////////////////////////
// inverse 4x4 matrix
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invert()
{
// If the 4th row is [0,0,0,1] then it is affine matrix and
// it has no projective transformation.
if(m[12] == 0 && m[13] == 0 && m[14] == 0 && m[15] == 1) this->invertAffine();
else this->invertGeneral();
return *this;
}

///////////////////////////////////////////////////////////////////////////////
// compute the inverse of 4x4 Euclidean transformation matrix
//
// Euclidean transformation is translation, rotation, and reflection.
// With Euclidean transform, only the position and orientation of the object
// will be changed. Euclidean transform does not change the shape of an object
// (no scaling). Length and angle are reserved.
//
// Use inverseAffine() if the matrix has scale and shear transformation.
//
// M = [ R | T ]
// [ --+-- ] (R denotes 3x3 rotation/reflection matrix)
// [ 0 | 1 ] (T denotes 1x3 translation matrix)
//
// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^T*y - R^T*T
// (R is orthogonal, R^-1 = R^T)
//
// [ R | T ]-1 [ R^T | -R^T * T ] (R denotes 3x3 rotation matrix)
// [ --+-- ] = [ ----+--------- ] (T denotes 1x3 translation)
// [ 0 | 1 ] [ 0 | 1 ] (R^T denotes R-transpose)
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertEuclidean()
{
// transpose 3x3 rotation matrix part
// | R^T | 0 |
// | ----+-- |
// | 0 | 1 |
float tmp;
tmp = m[1]; m[1] = m[4]; m[4] = tmp;
tmp = m[2]; m[2] = m[8]; m[8] = tmp;
tmp = m[6]; m[6] = m[9]; m[9] = tmp;

// compute translation part -R^T * T


// | 0 | -R^T x |
// | --+------- |
// | 0 | 0 |
float x = m[3];
float y = m[7];
float z = m[11];
m[3] = -(m[0] * x + m[1] * y + m[2] * z);
m[7] = -(m[4] * x + m[5] * y + m[6] * z);
m[11] = -(m[8] * x + m[9] * y + m[10]* z);

// last row should be unchanged (0,0,0,1)

return *this;
}

///////////////////////////////////////////////////////////////////////////////
// compute the inverse of a 4x4 affine transformation matrix
//
// Affine transformations are generalizations of Euclidean transformations.
// Affine transformation includes translation, rotation, reflection, scaling,
// and shearing. Length and angle are NOT preserved.
// M = [ R | T ]
// [ --+-- ] (R denotes 3x3 rotation/scale/shear matrix)
// [ 0 | 1 ] (T denotes 1x3 translation matrix)
//
// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^-1*y - R^-1*T
//
// [ R | T ]-1 [ R^-1 | -R^-1 * T ]
// [ --+-- ] = [ -----+---------- ]

KhoaCNTT – Trường ĐHBK 30


// [ 0 | 1 ] [ 0 + 1 ]
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertAffine()
{
// R^-1
Matrix3 r(m[0],m[1],m[2], m[4],m[5],m[6], m[8],m[9],m[10]);
r.invert();
m[0] = r[0]; m[1] = r[1]; m[2] = r[2];
m[4] = r[3]; m[5] = r[4]; m[6] = r[5];
m[8] = r[6]; m[9] = r[7]; m[10]= r[8];

// -R^-1 * T
float x = m[3];
float y = m[7];
float z = m[11];
m[3] = -(r[0] * x + r[1] * y + r[2] * z);
m[7] = -(r[3] * x + r[4] * y + r[5] * z);
m[11] = -(r[6] * x + r[7] * y + r[8] * z);

// last row should be unchanged (0,0,0,1)


//m[12] = m[13] = m[14] = 0.0f;
//m[15] = 1.0f;

return * this;
}

///////////////////////////////////////////////////////////////////////////////
// inverse matrix using matrix partitioning (blockwise inverse)
// It devides a 4x4 matrix into 4 of 2x2 matrices. It works in case of where
// det(A) != 0. If not, use the generic inverse method
// inverse formula.
// M = [ A | B ] A, B, C, D are 2x2 matrix blocks
// [ --+-- ] det(M) = |A| * |D - ((C * A^-1) * B)|
// [ C | D ]
//
// M^-1 = [ A' | B' ] A' = A^-1 - (A^-1 * B) * C'
// [ ---+--- ] B' = (A^-1 * B) * -D'
// [ C' | D' ] C' = -D' * (C * A^-1)
// D' = (D - ((C * A^-1) * B))^-1
//
// NOTE: I wrap with () if it it used more than once.
// The matrix is invertable even if det(A)=0, so must check det(A) before
// calling this function, and use invertGeneric() instead.
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertProjective()
{
// partition
Matrix2 a(m[0], m[1], m[4], m[5]);
Matrix2 b(m[2], m[3], m[6], m[7]);
Matrix2 c(m[8], m[9], m[12], m[13]);
Matrix2 d(m[10], m[11], m[14], m[15]);

// pre-compute repeated parts


a.invert(); // A^-1
Matrix2 ab = a * b; // A^-1 * B
Matrix2 ca = c * a; // C * A^-1
Matrix2 cab = ca * b; // C * A^-1 * B
Matrix2 dcab = d - cab; // D - C * A^-1 * B

// check determinant if |D - C * A^-1 * B| = 0


//NOTE: this function assumes det(A) is already checked. if |A|=0 then,
// cannot use this function.
float determinant = dcab[0] * dcab[3] - dcab[1] * dcab[2];
if(fabs(determinant) <= 0.00001f)
{
return identity();
}

// compute D' and -D'


Matrix2 d1 = dcab; // (D - C * A^-1 * B)
d1.invert(); // (D - C * A^-1 * B)^-1
Matrix2 d2 = -d1; // -(D - C * A^-1 * B)^-1

// compute C'
Matrix2 c1 = d2 * ca; // -D' * (C * A^-1)

// compute B'
Matrix2 b1 = ab * d2; // (A^-1 * B) * -D'

KhoaCNTT – Trường ĐHBK 31


// compute A'
Matrix2 a1 = a - (ab * c1); // A^-1 - (A^-1 * B) * C'

// assemble inverse matrix


m[0] = a1[0]; m[1] = a1[1]; /*|*/ m[2] = b1[0]; m[3] = b1[1];
m[4] = a1[2]; m[5] = a1[3]; /*|*/ m[6] = b1[2]; m[7] = b1[3];
/*-----------------------------+-----------------------------*/
m[8] = c1[0]; m[9] = c1[1]; /*|*/ m[10]= d1[0]; m[11]= d1[1];
m[12]= c1[2]; m[13]= c1[3]; /*|*/ m[14]= d1[2]; m[15]= d1[3];

return *this;
}

///////////////////////////////////////////////////////////////////////////////
// compute the inverse of a general 4x4 matrix using Cramer's Rule
// If cannot find inverse, return indentity matrix
// M^-1 = adj(M) / det(M)
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertGeneral()
{
// get cofactors of minor matrices
float cofactor0 = getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]);
float cofactor1 = getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]);
float cofactor2 = getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]);
float cofactor3 = getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);

// get determinant
float determinant = m[0] * cofactor0 - m[1] * cofactor1 + m[2] * cofactor2 - m[3] *
cofactor3;
if(fabs(determinant) <= 0.00001f)
{
return identity();
}

// get rest of cofactors for adj(M)


float cofactor4 = getCofactor(m[1],m[2],m[3], m[9],m[10],m[11], m[13],m[14],m[15]);
float cofactor5 = getCofactor(m[0],m[2],m[3], m[8],m[10],m[11], m[12],m[14],m[15]);
float cofactor6 = getCofactor(m[0],m[1],m[3], m[8],m[9], m[11], m[12],m[13],m[15]);
float cofactor7 = getCofactor(m[0],m[1],m[2], m[8],m[9], m[10], m[12],m[13],m[14]);

float cofactor8 = getCofactor(m[1],m[2],m[3], m[5],m[6], m[7], m[13],m[14],m[15]);


float cofactor9 = getCofactor(m[0],m[2],m[3], m[4],m[6], m[7], m[12],m[14],m[15]);
float cofactor10= getCofactor(m[0],m[1],m[3], m[4],m[5], m[7], m[12],m[13],m[15]);
float cofactor11= getCofactor(m[0],m[1],m[2], m[4],m[5], m[6], m[12],m[13],m[14]);

float cofactor12= getCofactor(m[1],m[2],m[3], m[5],m[6], m[7], m[9], m[10],m[11]);


float cofactor13= getCofactor(m[0],m[2],m[3], m[4],m[6], m[7], m[8], m[10],m[11]);
float cofactor14= getCofactor(m[0],m[1],m[3], m[4],m[5], m[7], m[8], m[9], m[11]);
float cofactor15= getCofactor(m[0],m[1],m[2], m[4],m[5], m[6], m[8], m[9], m[10]);

// build inverse matrix = adj(M) / det(M)


// adjugate of M is the transpose of the cofactor matrix of M
float invDeterminant = 1.0f / determinant;
m[0] = invDeterminant * cofactor0;
m[1] = -invDeterminant * cofactor4;
m[2] = invDeterminant * cofactor8;
m[3] = -invDeterminant * cofactor12;

m[4] = -invDeterminant * cofactor1;


m[5] = invDeterminant * cofactor5;
m[6] = -invDeterminant * cofactor9;
m[7] = invDeterminant * cofactor13;

m[8] = invDeterminant * cofactor2;


m[9] = -invDeterminant * cofactor6;
m[10]= invDeterminant * cofactor10;
m[11]= -invDeterminant * cofactor14;

m[12]= -invDeterminant * cofactor3;


m[13]= invDeterminant * cofactor7;
m[14]= -invDeterminant * cofactor11;
m[15]= invDeterminant * cofactor15;

return *this;
}

///////////////////////////////////////////////////////////////////////////////
// return determinant of 4x4 matrix
///////////////////////////////////////////////////////////////////////////////

KhoaCNTT – Trường ĐHBK 32


float Matrix4::getDeterminant()
{
return m[0] * getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]) -
m[1] * getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]) +
m[2] * getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]) -
m[3] * getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);
}

///////////////////////////////////////////////////////////////////////////////
// compute cofactor of 3x3 minor matrix without sign
// input params are 9 elements of the minor matrix
// NOTE: The caller must know its sign.
///////////////////////////////////////////////////////////////////////////////
float Matrix4::getCofactor(float m0, float m1, float m2,
float m3, float m4, float m5,
float m6, float m7, float m8)
{
return m0 * (m4 * m8 - m5 * m7) -
m1 * (m3 * m8 - m5 * m6) +
m2 * (m3 * m7 - m4 * m6);
}

///////////////////////////////////////////////////////////////////////////////
// translate this matrix by (x, y, z)
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::translate(const Vector3& v)
{
return translate(v.x, v.y, v.z);
}

Matrix4& Matrix4::translate(float x, float y, float z)


{
m[0] += m[12]*x; m[1] += m[13]*x; m[2] += m[14]*x; m[3] += m[15]*x;
m[4] += m[12]*y; m[5] += m[13]*y; m[6] += m[14]*y; m[7] += m[15]*y;
m[8] += m[12]*z; m[9] += m[13]*z; m[10]+= m[14]*z; m[11]+= m[15]*z;
return *this;
}

///////////////////////////////////////////////////////////////////////////////
// uniform scale
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::scale(float s)
{
return scale(s, s, s);
}

Matrix4& Matrix4::scale(float x, float y, float z)


{
m[0] = m[0]*x; m[1] = m[1]*x; m[2] = m[2]*x; m[3] = m[3]*x;
m[4] = m[4]*y; m[5] = m[5]*y; m[6] = m[6]*y; m[7] = m[7]*y;
m[8] = m[8]*z; m[9] = m[9]*z; m[10]= m[10]*z; m[11]= m[11]*z;
return *this;
}

///////////////////////////////////////////////////////////////////////////////
// build a rotation matrix with given angle(degree) and rotation axis, then
// multiply it with this object
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::rotate(float angle, const Vector3& axis)
{
return rotate(angle, axis.x, axis.y, axis.z);
}

Matrix4& Matrix4::rotate(float angle, float x, float y, float z)


{
float c = cosf(angle * DEG2RAD); // cosine
float s = sinf(angle * DEG2RAD); // sine
float xx = x * x;
float xy = x * y;
float xz = x * z;
float yy = y * y;
float yz = y * z;
float zz = z * z;

// build rotation matrix


Matrix4 m;
m[0] = xx * (1 - c) + c;
m[1] = xy * (1 - c) - z * s;
m[2] = xz * (1 - c) + y * s;
m[3] = 0;

KhoaCNTT – Trường ĐHBK 33


m[4] = xy * (1 - c) + z * s;
m[5] = yy * (1 - c) + c;
m[6] = yz * (1 - c) - x * s;
m[7] = 0;
m[8] = xz * (1 - c) - y * s;
m[9] = yz * (1 - c) + x * s;
m[10]= zz * (1 - c) + c;
m[11]= 0;
m[12]= 0;
m[13]= 0;
m[14]= 0;
m[15]= 1;

// multiply it
*this = m * (*this);

return *this;
}

Matrix4& Matrix4::rotateX(float angle)


{
float c = cosf(angle * DEG2RAD);
float s = sinf(angle * DEG2RAD);
float m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7],
m8 = m[8], m9 = m[9], m10= m[10], m11= m[11];

m[4] = m4 * c + m8 *-s;
m[5] = m5 * c + m9 *-s;
m[6] = m6 * c + m10*-s;
m[7] = m7 * c + m11*-s;
m[8] = m4 * s + m8 * c;
m[9] = m5 * s + m9 * c;
m[10]= m6 * s + m10* c;
m[11]= m7 * s + m11* c;

return *this;
}

Matrix4& Matrix4::rotateY(float angle)


{
float c = cosf(angle * DEG2RAD);
float s = sinf(angle * DEG2RAD);
float m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3],
m8 = m[8], m9 = m[9], m10= m[10], m11= m[11];

m[0] = m0 * c + m8 * s;
m[1] = m1 * c + m9 * s;
m[2] = m2 * c + m10* s;
m[3] = m3 * c + m11* s;
m[8] = m0 *-s + m8 * c;
m[9] = m1 *-s + m9 * c;
m[10]= m2 *-s + m10* c;
m[11]= m3 *-s + m11* c;

return *this;
}

Matrix4& Matrix4::rotateZ(float angle)


{
float c = cosf(angle * DEG2RAD);
float s = sinf(angle * DEG2RAD);
float m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3],
m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7];

m[0] = m0 * c + m4 *-s;
m[1] = m1 * c + m5 *-s;
m[2] = m2 * c + m6 *-s;
m[3] = m3 * c + m7 *-s;
m[4] = m0 * s + m4 * c;
m[5] = m1 * s + m5 * c;
m[6] = m2 * s + m6 * c;
m[7] = m3 * s + m7 * c;

return *this;
}

//===================================================

// GLUT CALLBACK functions

KhoaCNTT – Trường ĐHBK 34


void displayCB();
void reshapeCB(int w, int h);
void timerCB(int millisec);
void idleCB();
void keyboardCB(unsigned char key, int x, int y);
void mouseCB(int button, int stat, int x, int y);
void mouseMotionCB(int x, int y);

void initGL();
int initGLUT(int argc, char **argv);
bool initSharedMem();
void clearSharedMem();
void initLights();
void setCamera(float posX, float posY, float posZ, float targetX, float targetY, float
targetZ);
void drawString(const char *str, int x, int y, float color[4], void *font);
void drawString3D(const char *str, float pos[3], float color[4], void *font);
void showInfo();
void toOrtho();
void toPerspective();
void drawAxis(float size=2.5f);
void drawModel();
void anglesToMatrix(const Vector3 angles, Matrix4& matrix);
Matrix4 setFrustum(float l, float r, float b, float t, float n, float f);
Matrix4 setFrustum(float fovY, float aspectRatio, float front, float back);
Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f);

// constants
const int SCREEN_WIDTH = 400;
const int SCREEN_HEIGHT = 300;
const float CAMERA_DISTANCE = 6.0f;
const int TEXT_WIDTH = 8;
const int TEXT_HEIGHT = 13;
//const float DEG2RAD = 3.141593f / 180;

// global variables
void *font = GLUT_BITMAP_8_BY_13;
int screenWidth;
int screenHeight;
bool mouseLeftDown;
bool mouseRightDown;
float mouseX, mouseY;
float cameraAngleX;
float cameraAngleY;
float cameraDistance;
int drawMode = 0;
Matrix4 matrixView;
Matrix4 matrixModel;
Matrix4 matrixModelView; // = matrixView * matrixModel
Matrix4 matrixProjection;

///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{

/*
// Matrix4 usage examples =================================================
// Note that Matrix4 is row-major order

// create (construct) matrix


float a[16] = { 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2 };
Matrix4 m1; // with default ctor
Matrix4 m2(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); // with 16 elements
Matrix4 m3(a); // with array
Matrix4 m4(m3); // with copy ctor, same as Matrix4
m4 = m3;
//std::cout << m4 << std::endl;

// accessors (getter/setter)
m1.set(a); // init with array
m2.set(3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3); // init with 16 elements
m3 = m2; // init with assignemt operator
(=)
const float* a1 = m1.get(); // return pointer to matrix
elements
const float* a2 = m2.getTranspose(); // return transposed matrix
elements

// subscript operator [] to access each element


m1[0] = 3;

KhoaCNTT – Trường ĐHBK 35


std::cout << "FIRST ELEMENT: " << m1[0] << std::endl;
std::cout << " LAST ELEMENT: " << m1[15] << "\n\n";

// comparison (exact)
if(m1 == m2)
std::cout << "COMPARISON: EQUAL\n\n";
else
std::cout << "COMPARISON: NOT EQUAL\n\n";

// addition
m3 = m1 + m2; // M3 = M1 + M2
std::cout << "ADD:\n" << m3 << std::endl;

// subtraction
m3 = m1 - m2; // M3 = M1 - M2
std::cout << "SUBTRACT:\n" << m3 << std::endl;

// multiplication
m3 = m1 * m2; // M3 = M1 * M2
m3 *= m1; // M3 = M3 * M1 (=
glMultMatrixf(M1))
std::cout << "MULTIPLY:\n" << m3 << std::endl;

// scalar product (pre-mult only, not available M * s)


m3 = 5 * m1; // s * M
std::cout << "SCALAR PRODUCT:\n" << m3 << std::endl;

// vector multiplication
Vector3 v1 = Vector3(2,2,2);
Vector3 v2;
v2 = m1 * v1; // vector product: M * v
std::cout << "VECTOR MULTIPLY 1: " << v2 << std::endl;
v2 = v1 * m1; // pre-product: v * M
std::cout << "VECTOR MULTIPLY 2: " << v2 << "\n\n";

// transpose
m3.set(1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4);
m3.transpose(); // transpose
std::cout << "TRANSPOSE:\n" << m3 << std::endl;

// inverse of non-singluar
m3.set(1,0,0,0, 0,2,0,0, 0,0,3,0, 0,0,0,4); // non-singular M
m3.invert(); // inverse
std::cout << "INVERSE:\n" << m3 << std::endl;

// invert Euclidean (rotation/reflection only)


m3.set(-1,0,0,1, 0,0.70711f,-0.70711f,2, 0,0.70711f,0.70711f,3, 0,0,0,1);
m3.invertEuclidean(); // inverse explicitly
std::cout << "INVERSE EUCLIDEAN:\n" << m3 << std::endl;

// translate transform
m3.identity();
m3.translate(1, 2, 3); // = glTranslatef(x, y, z)
//m3.translate(v1);
std::cout << "TRANSLATE:\n" << m3 << std::endl;

// rotate transform with degree


m3.identity();
m3.rotate(45, 1,0,0); // = glRotatef(a, 1,0,0)
std::cout << "ROTATE:\n" << m3 << std::endl;

// rotate on basis axis (degree)


m3.rotateX(10); // = glRotatef(10, 1,0,0)
m3.rotateY(20); // = glRotatef(20, 0,1,0)
m3.rotateZ(30); // = glRotatef(30, 0,0,1)

// scale
m3.identity();
m3.scale(1, 2, 3); // = glScalef(x, y, z)
std::cout << "SCALE:\n" << m3 << std::endl;
*/
//=========================================================================

// init global vars


initSharedMem();

// init GLUT and GL


initGLUT(argc, argv);
initGL();

KhoaCNTT – Trường ĐHBK 36


// the last GLUT call (LOOP)
// window will be shown and display callback is triggered by events
// NOTE: this call never return main().
glutMainLoop(); /* Start GLUT event-processing loop */

return 0;
}

///////////////////////////////////////////////////////////////////////////////
// draw the local axis of an object
///////////////////////////////////////////////////////////////////////////////
void drawAxis(float size)
{
glDepthFunc(GL_ALWAYS); // to avoid visual artifacts with grid lines
glDisable(GL_LIGHTING);

// draw axis
glLineWidth(3);
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0, 0, 0);
glVertex3f(size, 0, 0);
glColor3f(0, 1, 0);
glVertex3f(0, 0, 0);
glVertex3f(0, size, 0);
glColor3f(0, 0, 1);
glVertex3f(0, 0, 0);
glVertex3f(0, 0, size);
glEnd();
glLineWidth(1);

// draw arrows(actually big square dots)


glPointSize(5);
glBegin(GL_POINTS);
glColor3f(1, 0, 0);
glVertex3f(size, 0, 0);
glColor3f(0, 1, 0);
glVertex3f(0, size, 0);
glColor3f(0, 0, 1);
glVertex3f(0, 0, size);
glEnd();
glPointSize(1);

// restore default settings


glEnable(GL_LIGHTING);
glDepthFunc(GL_LEQUAL);
}

///////////////////////////////////////////////////////////////////////////////
// draw a model (tetrahedron)
///////////////////////////////////////////////////////////////////////////////
void drawModel()
{
glColor3f(1, 1, 1);
glBegin(GL_TRIANGLES);
glNormal3f(0.6667f, 0.6667f, 0.3334f);
glVertex3f(1, 0, 0);
glVertex3f(0, 1, 0);
glVertex3f(0, 0, 2);
/*
glNormal3f(-0.6667f, 0.6667f, 0.3334f);
glVertex3f(-1, 0, 0);
glVertex3f(0, 0, 2);
glVertex3f(0, 1, 0);

glNormal3f(0, 0, -1);
glVertex3f(1, 0, 0);
glVertex3f(0, 0, 2);
glVertex3f(-1, 0, 0);

glNormal3f(0, -1, 0);


glVertex3f(1, 0, 0);
glVertex3f(-1, 0, 0);
glVertex3f(0, 1, 0);
*/
glEnd();
}

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

KhoaCNTT – Trường ĐHBK 37


// initialize GLUT for windowing
///////////////////////////////////////////////////////////////////////////////
int initGLUT(int argc, char **argv)
{
// GLUT stuff for windowing
// initialization openGL window.
// it is called before any other GLUT routine
glutInit(&argc, argv);

glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); // display mode

glutInitWindowSize(screenWidth, screenHeight); // window size

glutInitWindowPosition(100, 100); // window location

// finally, create a window with openGL context


// Window will not displayed until glutMainLoop() is called
// it returns a unique ID
int handle = glutCreateWindow(argv[0]); // param is the title of window

// register GLUT callback functions


glutDisplayFunc(displayCB);
glutTimerFunc(33, timerCB, 33); // redraw only every given millisec
//glutIdleFunc(idleCB); // redraw whenever system is idle
glutReshapeFunc(reshapeCB);
glutKeyboardFunc(keyboardCB);
glutMouseFunc(mouseCB);
glutMotionFunc(mouseMotionCB);

return handle;
}

///////////////////////////////////////////////////////////////////////////////
// initialize OpenGL
// disable unused features
///////////////////////////////////////////////////////////////////////////////
void initGL()
{
glShadeModel(GL_SMOOTH); // shading mathod: GL_SMOOTH or GL_FLAT
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment

// enable /disable features


glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);

// enable /disable features


glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);

// track material ambient and diffuse from surface color, call it before
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

glClearColor(0, 0, 0, 0); // background color


glClearStencil(0); // clear stencil buffer
glClearDepth(1.0f); // 0 is near, 1 is far
glDepthFunc(GL_LEQUAL);

initLights();
}

///////////////////////////////////////////////////////////////////////////////
// write 2d text using GLUT
// The projection matrix must be set to orthogonal before call this function.
///////////////////////////////////////////////////////////////////////////////
void drawString(const char *str, int x, int y, float color[4], void *font)
{

KhoaCNTT – Trường ĐHBK 38


glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT); // lighting and color mask
glDisable(GL_LIGHTING); // need to disable lighting for proper text color
glDisable(GL_TEXTURE_2D);

glColor4fv(color); // set text color


glRasterPos2i(x, y); // place text position

// loop all characters in the string


while(*str)
{
glutBitmapCharacter(font, *str);
++str;
}

glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glPopAttrib();
}

///////////////////////////////////////////////////////////////////////////////
// draw a string in 3D space
///////////////////////////////////////////////////////////////////////////////
void drawString3D(const char *str, float pos[3], float color[4], void *font)
{
glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT); // lighting and color mask
glDisable(GL_LIGHTING); // need to disable lighting for proper text color
glDisable(GL_TEXTURE_2D);

glColor4fv(color); // set text color


glRasterPos3fv(pos); // place text position

// loop all characters in the string


while(*str)
{
glutBitmapCharacter(font, *str);
++str;
}

glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glPopAttrib();
}

///////////////////////////////////////////////////////////////////////////////
// initialize global variables
///////////////////////////////////////////////////////////////////////////////
bool initSharedMem()
{
screenWidth = SCREEN_WIDTH;
screenHeight = SCREEN_HEIGHT;

mouseLeftDown = mouseRightDown = false;


mouseX = mouseY = 0;

cameraAngleX = cameraAngleY = 0;
cameraDistance = CAMERA_DISTANCE;

drawMode = 0; // 0:fill, 1: wireframe, 2:points

return true;
}

///////////////////////////////////////////////////////////////////////////////
// initialize lights
///////////////////////////////////////////////////////////////////////////////
void initLights()
{
// set up light colors (ambient, diffuse, specular)
GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f}; // ambient light
GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f}; // diffuse light
GLfloat lightKs[] = {1, 1, 1, 1}; // specular light
glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);

// position the light


float lightPos[4] = {0, 0, 20, 1}; // positional light
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

KhoaCNTT – Trường ĐHBK 39


glEnable(GL_LIGHT0); // MUST enable each light source after
configuration
}

///////////////////////////////////////////////////////////////////////////////
// set camera position and lookat direction
///////////////////////////////////////////////////////////////////////////////
void setCamera(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float
centerZ)
{
Vector3 eye(eyeX, eyeY, eyeZ);
Vector3 center(centerX, centerY, centerZ);
Vector3 up(0, 1, 0); // assume the camera is always straight up (no roll)

Vector3 forward = (eye - center).normalize();


Vector3 left = up.cross(forward).normalize();
up = forward.cross(left); // up vector is unit length here

// set inverse of rotation matrix: M^-1 = M^T if it is Euclidean transform


matrixView.identity();
matrixView.setRow(0, left);
matrixView.setRow(1, up);
matrixView.setRow(2, forward);

// set translation column


// The result is product of rotation(Mr) and translation (Mt): Mv = Mr * Mt
Vector3 trans(left.dot(-eye), up.dot(-eye), forward.dot(-eye));
matrixView.setColumn(3, trans);
}

///////////////////////////////////////////////////////////////////////////////
// display info messages
///////////////////////////////////////////////////////////////////////////////
void showInfo()
{
// backup current model-view matrix
glPushMatrix(); // save current modelview matrix
glLoadIdentity(); // reset modelview matrix

// set to 2D orthogonal projection


glMatrixMode(GL_PROJECTION); // switch to projection matrix
glPushMatrix(); // save current projection matrix
glLoadIdentity(); // reset projection matrix
gluOrtho2D(0, screenWidth, 0, screenHeight); // set to orthogonal projection

float color[4] = {1, 1, 1, 1};

stringstream ss;
ss << std::fixed << std::setprecision(3);

drawString("=== View Matrix ===", 0, screenHeight-TEXT_HEIGHT, color, font);


ss << "[" << std::setw(8) << matrixView[0] << std::setw(8) << matrixView[1] <<
std::setw(8) << matrixView[2] << std::setw(8) << matrixView[3] << "]" << ends;
drawString(ss.str().c_str(), 0, screenHeight-(2*TEXT_HEIGHT), color, font);
ss.str("");
ss << "[" << std::setw(8) << matrixView[4] << std::setw(8) << matrixView[5] <<
std::setw(8) << matrixView[6] << std::setw(8) << matrixView[7] << "]" << ends;
drawString(ss.str().c_str(), 0, screenHeight-(3*TEXT_HEIGHT), color, font);
ss.str("");
ss << "[" << std::setw(8) << matrixView[8] << std::setw(8) << matrixView[9] <<
std::setw(8) << matrixView[10]<< std::setw(8) << matrixView[11]<< "]" << ends;
drawString(ss.str().c_str(), 0, screenHeight-(4*TEXT_HEIGHT), color, font);
ss.str("");
ss << "[" << std::setw(8) << matrixView[12]<< std::setw(8) << matrixView[13]<<
std::setw(8) << matrixView[14]<< std::setw(8) << matrixView[15]<< "]" << ends;
drawString(ss.str().c_str(), 0, screenHeight-(5*TEXT_HEIGHT), color, font);
ss.str("");

drawString("=== Model Matrix ===", 0, 4*TEXT_HEIGHT, color, font);


ss << "[" << std::setw(8) << matrixModel[0] << std::setw(8) << matrixModel[1] <<
std::setw(8) << matrixModel[2] << std::setw(8) << matrixModel[3] << "]" << ends;
drawString(ss.str().c_str(), 0, 3*TEXT_HEIGHT, color, font);
ss.str("");
ss << "[" << std::setw(8) << matrixModel[4] << std::setw(8) << matrixModel[5] <<
std::setw(8) << matrixModel[6] << std::setw(8) << matrixModel[7] << "]" << ends;
drawString(ss.str().c_str(), 0, 2*TEXT_HEIGHT, color, font);
ss.str("");
ss << "[" << std::setw(8) << matrixModel[8] << std::setw(8) << matrixModel[9] <<
std::setw(8) << matrixModel[10]<< std::setw(8) << matrixModel[11]<< "]" << ends;
drawString(ss.str().c_str(), 0, TEXT_HEIGHT, color, font);

KhoaCNTT – Trường ĐHBK 40


ss.str("");
ss << "[" << std::setw(8) << matrixModel[12]<< std::setw(8) << matrixModel[13]<<
std::setw(8) << matrixModel[14]<< std::setw(8) << matrixModel[15]<< "]" << ends;
drawString(ss.str().c_str(), 0, 0, color, font);
ss.str("");

// unset floating format


ss << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);

// restore projection matrix


glPopMatrix(); // restore to previous projection matrix

// restore modelview matrix


glMatrixMode(GL_MODELVIEW); // switch to modelview matrix
glPopMatrix(); // restore to previous modelview matrix
}

///////////////////////////////////////////////////////////////////////////////
// set projection matrix as orthogonal
///////////////////////////////////////////////////////////////////////////////
void toOrtho()
{
// set viewport to be the entire window
glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);

// set orthographic viewing frustum


glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, screenWidth, 0, screenHeight, -1, 1);

// switch to modelview matrix in order to set scene


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

///////////////////////////////////////////////////////////////////////////////
// set the projection matrix as perspective
///////////////////////////////////////////////////////////////////////////////
void toPerspective()
{
// set viewport to be the entire window
glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);

// set perspective viewing frustum


glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, (float)(screenWidth)/screenHeight, 1.0f, 1000.0f); // FOV,
AspectRatio, NearClip, FarClip

// switch to modelview matrix in order to set scene


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

///////////////////////////////////////////////////////////////////////////////
// convert Euler angles(x,y,z) to matrix4
// Each column of the rotation matrix represents left, up and forward axis.
// The order of rotation is Roll->Yaw->Pitch (Rx*Ry*Rz)
// Rx: rotation about X-axis, pitch
// Ry: rotation about Y-axis, yaw(heading)
// Rz: rotation about Z-axis, roll
// Rx Ry Rz
// |1 0 0| | Cy 0 Sy| |Cz -Sz 0| | CyCz -CySz Sy |
// |0 Cx -Sx|*| 0 1 0|*|Sz Cz 0| = | SxSyCz+CxSz -SxSySz+CxCz -SxCy|
// |0 Sx Cx| |-Sy 0 Cy| | 0 0 1| |-CxSyCz+SxSz CxSySz+SxCz CxCy|
///////////////////////////////////////////////////////////////////////////////
void anglesToMatrix(const Vector3 angles, Matrix4& matrix)
{
const float DEG2RAD = 3.141593f / 180;
float sx, sy, sz, cx, cy, cz, theta;
Vector3 left, up, forward;

// rotation angle about X-axis (pitch)


theta = angles.x * DEG2RAD;
sx = sinf(theta);
cx = cosf(theta);

// rotation angle about Y-axis (yaw)


theta = angles.y * DEG2RAD;
sy = sinf(theta);

KhoaCNTT – Trường ĐHBK 41


cy = cosf(theta);

// rotation angle about Z-axis (roll)


theta = angles.z * DEG2RAD;
sz = sinf(theta);
cz = cosf(theta);

// determine left axis


left.x = cy*cz;
left.y = sx*sy*cz + cx*sz;
left.z = -cx*sy*cz + sx*sz;

// determine up axis
up.x = -cy*sz;
up.y = -sx*sy*sz + cx*cz;
up.z = cx*sy*sz + sx*cz;

// determine forward axis


forward.x = sy;
forward.y = -sx*cy;
forward.z = cx*cy;

// write back to matrix


matrix.setColumn(0, left);
matrix.setColumn(1, up);
matrix.setColumn(2, forward);
}

///////////////////////////////////////////////////////////////////////////////
// set a perspective frustum with 6 params similar to glFrustum()
// (left, right, bottom, top, near, far)
// Note: this is for row-major notation. OpenGL needs transpose it
///////////////////////////////////////////////////////////////////////////////
Matrix4 setFrustum(float l, float r, float b, float t, float n, float f)
{
Matrix4 mat;
mat[0] = 2 * n / (r - l);
mat[2] = (r + l) / (r - l);
mat[5] = 2 * n / (t - b);
mat[6] = (t + b) / (t - b);
mat[10] = -(f + n) / (f - n);
mat[11] = -(2 * f * n) / (f - n);
mat[14] = -1;
mat[15] = 0;
return mat;
}

///////////////////////////////////////////////////////////////////////////////
// set a symmetric perspective frustum with 4 params similar to gluPerspective
// (vertical field of view, aspect ratio, near, far)
///////////////////////////////////////////////////////////////////////////////
Matrix4 setFrustum(float fovY, float aspectRatio, float front, float back)
{
float tangent = tanf(fovY/2 * DEG2RAD); // tangent of half fovY
float height = front * tangent; // half height of near plane
float width = height * aspectRatio; // half width of near plane

// params: left, right, bottom, top, near, far


return setFrustum(-width, width, -height, height, front, back);
}

///////////////////////////////////////////////////////////////////////////////
// set a orthographic frustum with 6 params similar to glOrtho()
// (left, right, bottom, top, near, far)
// Note: this is for row-major notation. OpenGL needs transpose it
///////////////////////////////////////////////////////////////////////////////
Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f)
{
Matrix4 mat;
mat[0] = 2 / (r - l);
mat[3] = -(r + l) / (r - l);
mat[5] = 2 / (t - b);
mat[7] = -(t + b) / (t - b);
mat[10] = -2 / (f - n);
mat[11] = -(f + n) / (f - n);
return mat;
}

//=============================================================================
// CALLBACKS

KhoaCNTT – Trường ĐHBK 42


//=============================================================================

void displayCB()
{
// clear buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// save the initial ModelView matrix before modifying ModelView matrix


glPushMatrix();

// tramsform camera
matrixView.identity();
matrixView.rotate(cameraAngleY, 0, 1, 0);
matrixView.rotate(cameraAngleX, 1, 0, 0);
matrixView.translate(0, 0, -cameraDistance);
// The equivalent code for using OpenGL routine is:
// glTranslatef(0, 0, -cameraDistance);
// glRotatef(cameraAngleX, 1, 0, 0); // pitch
// glRotatef(cameraAngleY, 0, 1, 0); // heading

// Copy view matrix to OpenGL


glLoadMatrixf(matrixView.getTranspose());
// Compute model matrix
matrixModel.identity();
//matrixModel.rotateZ(45); // rotate 45 degree on Z-axis
matrixModel.rotateY(45); // rotate 45 degree on Y-axis
matrixModel.translate(0, 1, 0); // move 2 unit up

// Compute modelview matrix


matrixModelView = matrixView * matrixModel;

// Copy modelview matrix to OpenGL


glLoadMatrixf(matrixModelView.getTranspose());

drawAxis();
drawModel();

// Draw info messages


showInfo();
glPopMatrix();
glutSwapBuffers();
}

void reshapeCB(int w, int h)


{
screenWidth = w;
screenHeight = h;

// set viewport to be the entire window


glViewport(0, 0, (GLsizei)w, (GLsizei)h);

// set perspective viewing frustum


glMatrixMode(GL_PROJECTION);
matrixProjection = setFrustum(45, (float)w/h, 1.0f, 100.0f);
glLoadMatrixf(matrixProjection.getTranspose());
// The equivalent OpenGL call
// gluPerspective(45.0f, (float)(w)/h, 1.0f, 100.0f); // FOV, AspectRatio, NearClip,
FarClip

// DEBUG
std::cout << "===== Projection Matrix =====\n";
std::cout << matrixProjection << std::endl;

// switch to modelview matrix in order to set scene


glMatrixMode(GL_MODELVIEW);
}

void timerCB(int millisec)


{
glutTimerFunc(millisec, timerCB, millisec);
glutPostRedisplay();
}

void idleCB()
{
glutPostRedisplay();
}

KhoaCNTT – Trường ĐHBK 43


void keyboardCB(unsigned char key, int x, int y)
{
switch(key)
{
case 27: // ESCAPE
exit(0);
break;
case ' ':
break;
case 'd': // switch rendering modes (fill -> wire -> point)
case 'D':
drawMode = ++drawMode % 3;
if(drawMode == 0) // fill mode
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
else if(drawMode == 1) // wireframe mode
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
}
else // point mode
{
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
}
break;

default:
;
}
}

void mouseCB(int button, int state, int x, int y)


{
mouseX = x;
mouseY = y;

if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseLeftDown = true;
}
else if(state == GLUT_UP) mouseLeftDown = false;
}

else if(button == GLUT_RIGHT_BUTTON)


{
if(state == GLUT_DOWN)
{
mouseRightDown = true;
}
else if(state == GLUT_UP) mouseRightDown = false;
}
}

void mouseMotionCB(int x, int y)


{
if(mouseLeftDown)
{
cameraAngleY += (x - mouseX);
cameraAngleX += (y - mouseY);
mouseX = x;
mouseY = y;
}
if(mouseRightDown)
{
cameraDistance -= (y - mouseY) * 0.2f;
mouseY = y;
}
}//end

KhoaCNTT – Trường ĐHBK 44


Kết quả chạy chương trình
1) Xem các giao diện các vị trí của đối tượng

2) Xem kết quả tính toán ma trận

3. BÀI TẬP
Viết chương trình thực hiện các yêu cầu sau:
1) Cho điểm Pobj(xobj, yobj, zobj, 1) trong hệ tọa độ thế giới thực (world wpace), với xobj,
yobj, zobj là các giá trị được trích từ mã sinh viên.
Xác định các ma trận biến đổi và điểm Pw(xw, yw, zw, 1) khi thực hiện các phép biến đổi
sau:

KhoaCNTT – Trường ĐHBK 45


 Phép biến đổi Tịnh tiến với dx, dy, dz
 Quay quanh trục Ox, Oy, Oz một góc tùy chọn
 Quay quanh một trục PQ có P(xp, yp, zp), Q(xq, yq, zq)
2) Xét điểm Pw(xw, yw, zw, 1) trong hệ tọa độ thế giới thực (World Space) được tính toán
từ câu 1.
Xác định các ma trận biến đổi và và xác định điểm Pcam(xcam, ycam, zcam, 1) trong hệ tọa
độ camera space khi thực hiện:
 Phép biến đổi camera đặt tại eye = (xeye, yeye, zeye), nhìn vào tâm center = (x2,
y2, z2), hướng lên k = (0, 1, 0)]
3) Cho điểm Pcam(xcam, ycam, zcam, 1) trong hệ tọa độ camera space là kết quả của câu 2.
Xác định các ma trận biến đổi và và xác định điểm Pclip(xclip, yclip, zclip, wclip) trong
clipping/projection space khi thực hiện:
 Phép chiếu song song
 Phép chiếu xiên
 Phép chiếu trực giao
 Phép chiếu phối cảnh
#include <GL/glut.h>
#include <iostream>
#include <cmath>

// Điểm Pobj(xobj, yobj, zobj, 1) trong hệ tọa độ thế giới thực (world wpace)
GLfloat xobj = 2.0f;
GLfloat yobj = 3.0f;
GLfloat zobj = 1.0f;

// Điểm Pw(xw, yw, zw, 1) khi thực hiện các phép biến đổi
GLfloat xw, yw, zw;

// Phép biến đổi tịnh tiến với dx, dy, dz


void translate(GLfloat dx, GLfloat dy, GLfloat dz) {
xw = xobj + dx;
yw = yobj + dy;
zw = zobj + dz;
}

// Phép biến đổi quay quanh trục Ox, Oy, Oz một góc theta
void rotate(GLfloat angle, GLfloat axis_x, GLfloat axis_y, GLfloat axis_z) {
GLfloat rad = angle * M_PI / 180.0f;

KhoaCNTT – Trường ĐHBK 46


GLfloat cos_theta = cos(rad);
GLfloat sin_theta = sin(rad);

xw = xobj * (cos_theta + (1 - cos_theta) * axis_x * axis_x)


+ yobj * ((1 - cos_theta) * axis_x * axis_y - sin_theta * axis_z)
+ zobj * ((1 - cos_theta) * axis_x * axis_z + sin_theta * axis_y);

yw = xobj * ((1 - cos_theta) * axis_y * axis_x + sin_theta * axis_z)


+ yobj * (cos_theta + (1 - cos_theta) * axis_y * axis_y)
+ zobj * ((1 - cos_theta) * axis_y * axis_z - sin_theta * axis_x);

zw = xobj * ((1 - cos_theta) * axis_z * axis_x - sin_theta * axis_y)


+ yobj * ((1 - cos_theta) * axis_z * axis_y + sin_theta * axis_x)
+ zobj * (cos_theta + (1 - cos_theta) * axis_z * axis_z);
}

// Phép biến đổi quay quanh trục PQ có P(xp, yp, zp), Q(xq, yq, zq)
void rotatePQ(GLfloat angle, GLfloat xp, GLfloat yp, GLfloat zp, GLfloat xq,
GLfloat yq, GLfloat zq) {
GLfloat axis_x = xq - xp;
GLfloat axis_y = yq - yp;
GLfloat axis_z = zq - zp;
GLfloat length = sqrt(axis_x * axis_x + axis_y * axis_y + axis_z * axis_z);
axis_x /= length;
axis_y /= length;
axis_z /= length;
GLfloat px = xobj - xp;
GLfloat py = yobj - yp;
GLfloat pz = zobj - zp;
GLfloat cos_theta = cos(angle * M_PI / 180.0f);
GLfloat sin_theta = sin(angle * M_PI / 180.0f);

xw = px * (cos_theta + (1 - cos_theta) * axis_x * axis_x)


+ py * ((1 - cos_theta) * axis_x * axis_y - sin_theta * axis_z)
+ pz * ((1 - cos_theta) * axis_x * axis_z + sin_theta * axis_y)
+ xp;

yw = px * ((1 - cos_theta) * axis_y * axis_x + sin_theta * axis_z)


KhoaCNTT – Trường ĐHBK 47
+ py * (cos_theta + (1 - cos_theta) * axis_y * axis_y)
+ pz * ((1 - cos_theta) * axis_y * axis_z - sin_theta * axis_x)
+ yp;

zw = px * ((1 - cos_theta) * axis_z * axis_x - sin_theta * axis_y)


+ py * ((1 - cos_theta) * axis_z * axis_y + sin_theta * axis_x)
+ pz * (cos_theta + (1 - cos_theta) * axis_z * axis_z)
+ zp;
}

// Hàm hiển thị


void display() {
// Xóa màn hình
glClear(GL_COLOR_BUFFER_BIT);
// Vẽ điểm Pobj(xobj, yobj, zobj, 1)
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f); // Màu đỏ
glVertex3f(xobj, yobj, zobj);
glEnd();

------------------------------------------------

KhoaCNTT – Trường ĐHBK 48

You might also like