Kompyuter grafikasi: OpenGL 2-qism

Salom. Bugun yana o'sha kompyuter grafikasi haqida gapirmoqchiman. Oldingiz maqolamni o'qigan bo'lsangiz u yerda faqat matematika haqida gapirganman. Endi shu matematikani haqiqiy dasturlashda ko'ramiz.



Buning uchun bizga yana OpenGL va SDL kerak bo'ladi.

Avvalo VS2010 da bitta Console Application (C/C++) yaratib, main.cpp ni ham qo'shamiz o'sha proyektga va ishni boshlaymiz.

Asosiy ishimiy matritsalar bilan ishlash bo'ladi.

Matritsani strukturasini yaratish
typedef struct _MATRIX
{
	int n, m; /* Matritsani o'lchami */
	double ** data; /* Matritsa qiymatlari */
} MATRIX, * PMATRIX;

Endi yangi matritsani yaratadigan ya o'chirish funksiyani
PMATRIX new_matrix(int n, int m)
{
	PMATRIX pm = (PMATRIX)malloc(sizeof(_MATRIX));
	pm->data = (double **)malloc(n * sizeof(double));
	pm->n = n;
	pm->m = m;

	for(int i = 0; i < n; i++)
	{
		pm->data[i] = (double *)malloc(m * sizeof(double));
		for(int j = 0; j < m; j++)
			pm->data[i][j] = i == j ? 1 : 0;
	}

	return pm;
}

void free_matrix(PMATRIX pm)
{
	free(pm->data);
	pm->data = NULL;

	free(pm);
	pm = NULL;
}


Eng ko'p ishlatiladigan funksiyamiz ya'ni matritsalarni ko'paytirish
void mult(PMATRIX m1, PMATRIX *m2)
{
	PMATRIX result = new_matrix((*m2)->n, (*m2)->m);
	for(int nn = 0; nn < (*m2)->n; nn++)
	{
		for(int mm = 0; mm < (*m2)->m; mm++)
		{
			result->data[nn][mm] = 0;
			for(int k = 0; k <(*m2)->n; k++)
				result->data[nn][mm] += m1->data[nn][k] * (*m2)->data[k][mm];
		}
	}

	free_matrix(*m2);
	*m2 = result;
}


Asosiy funksiyalar transform va rotate (scaleni yozmadim)
void transform(PMATRIX *point, int dx, int dy, int dz)
{
	PMATRIX m = new_matrix(4, 4); 
	m->data[0][3] = dx;
	m->data[1][3] = dy;
	m->data[2][3] = dz;

	mult(m, point);

	free_matrix(m);
}

void rotate(PMATRIX *point, double x, double y, double z, float angle)
{
	angle = angle * 3.1415926 / 180.0;

	PMATRIX rX = new_matrix(4, 4); 
	rX->data[1][1] = cos(angle * x);
	rX->data[2][1] = sin(angle * x);
	rX->data[1][2] = -sin(angle * x);
	rX->data[2][2] = cos(angle * x);

	PMATRIX rY = new_matrix(4, 4); 
	rY->data[0][0] = cos(-angle * y);
	rY->data[2][0] = sin(-angle * y);
	rY->data[0][2] = -sin(-angle * y);
	rY->data[2][2] = cos(-angle * y);

	PMATRIX rZ = new_matrix(4, 4); 
	rZ->data[0][0] = cos(angle * z);
	rZ->data[1][0] = sin(angle * z);
	rZ->data[0][1] = -sin(angle * z);
	rZ->data[1][1] = cos(angle * z);

	if (x != 0.0)
		mult(rX, point);

	if (y != 0.0)
		mult(rY, point);

	if (z != 0.0)
		mult(rZ, point);

	free_matrix(rX);
	free_matrix(rY);
	free_matrix(rZ);
}


Yana 2 ta funksiyami qoldi, ular kordinalatalar oqi va nuqtani chizish uchun ishlatiladi. Mani holatimda n — matritsani qatorlari soni, m — ustunlari soni sifatida ishlatilgan. Kodda izoh keltirmadim chunki bundan oldingi maqolamda hamma matritsalarni keltirganman. Shularni faqat kodga o'tkazdim. Qolga sizga notanish funksiyalar bilan asta sekin tanishamiz.

Shunaq qilib oxirgi natija:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>

#include <SDL.h>
#define PROGRAM_NAME "Matritsalar"


typedef struct _MATRIX
{
	int n, m; /* Matritsani o'lchami */
	double ** data; /* Matritsa qiymatlari */
} MATRIX, * PMATRIX;

PMATRIX new_matrix(int n, int m)
{
	PMATRIX pm = (PMATRIX)malloc(sizeof(_MATRIX));
	pm->data = (double **)malloc(n * sizeof(double));
	pm->n = n;
	pm->m = m;

	for(int i = 0; i < n; i++)
	{
		pm->data[i] = (double *)malloc(m * sizeof(double));
		for(int j = 0; j < m; j++)
			pm->data[i][j] = i == j ? 1 : 0;
	}

	return pm;
}

void free_matrix(PMATRIX pm)
{
	free(pm->data);
	pm->data = NULL;

	free(pm);
	pm = NULL;
}

void mult(PMATRIX m1, PMATRIX *m2)
{
	PMATRIX result = new_matrix((*m2)->n, (*m2)->m);
	for(int nn = 0; nn < (*m2)->n; nn++)
	{
		for(int mm = 0; mm < (*m2)->m; mm++)
		{
			result->data[nn][mm] = 0;
			for(int k = 0; k <(*m2)->n; k++)
				result->data[nn][mm] += m1->data[nn][k] * (*m2)->data[k][mm];
		}
	}

	free_matrix(*m2);
	*m2 = result;
}


void transform(PMATRIX *point, int dx, int dy, int dz)
{
	PMATRIX m = new_matrix(4, 4); 
	m->data[0][3] = dx;
	m->data[1][3] = dy;
	m->data[2][3] = dz;

	mult(m, point);

	free_matrix(m);
}

void rotate(PMATRIX *point, double x, double y, double z, float angle)
{
	angle = angle * 3.1415926 / 180.0;

	PMATRIX rX = new_matrix(4, 4); 
	rX->data[1][1] = cos(angle * x);
	rX->data[2][1] = sin(angle * x);
	rX->data[1][2] = -sin(angle * x);
	rX->data[2][2] = cos(angle * x);

	PMATRIX rY = new_matrix(4, 4); 
	rY->data[0][0] = cos(-angle * y);
	rY->data[2][0] = sin(-angle * y);
	rY->data[0][2] = -sin(-angle * y);
	rY->data[2][2] = cos(-angle * y);

	PMATRIX rZ = new_matrix(4, 4); 
	rZ->data[0][0] = cos(angle * z);
	rZ->data[1][0] = sin(angle * z);
	rZ->data[0][1] = -sin(angle * z);
	rZ->data[1][1] = cos(angle * z);

	if (x != 0.0)
		mult(rX, point);

	if (y != 0.0)
		mult(rY, point);

	if (z != 0.0)
		mult(rZ, point);

	free_matrix(rX);
	free_matrix(rY);
	free_matrix(rZ);
}

void draw_coords()
{
	glBegin(GL_LINES);

	glColor3ub(255, 0, 0);
	glVertex3i(-50, 0, 0);
	glVertex3i(100, 0, 0);

	glColor3ub(0, 255, 0);
	glVertex3i(0, -50, 0);
	glVertex3i(0, 100, 0);

	glColor3ub(0, 0, 255);
	glVertex3i(0, 0, -50);
	glVertex3i(0, 0, 100);

	glEnd();
}

void draw_matrix_point(PMATRIX m)
{
	int x = m->data[0][0];
	int y = m->data[1][0];
	int z = m->data[2][0];

	glBegin(GL_QUADS);

	glColor3ub(255, 255, 0);

	//past qismi
	glVertex3i(x - 1, y - 1, z - 1);
	glVertex3i(x + 1, y - 1, z - 1);
	glVertex3i(x + 1, y + 1, z - 1);
	glVertex3i(x - 1, y + 1, z - 1);

	//yuqorisi
	glVertex3i(x - 1, y - 1, z + 1);
	glVertex3i(x + 1, y - 1, z + 1);
	glVertex3i(x + 1, y + 1, z + 1);
	glVertex3i(x - 1, y + 1, z + 1);

	glVertex3i(x - 1, y - 1, z - 1);
	glVertex3i(x + 1, y - 1, z - 1);
	glVertex3i(x + 1, y - 1, z + 1);
	glVertex3i(x - 1, y - 1, z + 1);

	glVertex3i(x - 1, y + 1, z - 1);
	glVertex3i(x + 1, y + 1, z - 1);
	glVertex3i(x + 1, y + 1, z + 1);
	glVertex3i(x - 1, y + 1, z + 1);

	glVertex3i(x - 1, y - 1, z - 1);
	glVertex3i(x - 1, y - 1, z + 1);
	glVertex3i(x - 1, y + 1, z + 1);
	glVertex3i(x - 1, y + 1, z - 1);


	glVertex3i(x + 1, y - 1, z - 1);
	glVertex3i(x + 1, y - 1, z + 1);
	glVertex3i(x + 1, y + 1, z + 1);
	glVertex3i(x + 1, y + 1, z - 1);

	glEnd();
}

void sdldie(const char *msg)
{
    printf("%s: %s\n", msg, SDL_GetError());
    SDL_Quit();
    exit(1);
}

int main(int argc, char *argv[])
{
	//X=50, Y=0, Z=50 joydagi nuqta matritsasini yaratish
	PMATRIX point = new_matrix(4, 1);
	point->data[0][0] = 50;
	point->data[1][0] = 0;
	point->data[2][0] = 50;
	point->data[3][0] = 1;

	int windowWidth = 640, windowHeight = 480;
	int isRunning = 1;

	SDL_Window *mainwindow; /* Oynda o'zgaruvchisi */
    SDL_GLContext maincontext; /* OpenGL konteksi o'zgaruvchisi */

    if (SDL_Init(SDL_INIT_VIDEO) < 0) /* Initsalizatsiya SDL. Umuman tekshirish. */
        sdldie("Initsalizatsiya SDL da xatolik"); /* Agar xatolik bo'lsa */
 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); /* Double buffer qo'shish */
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); /* Double buffer qo'shish */

    //Oyna yaratish, o'lchami 300x450 bo'lgan
    mainwindow = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        windowWidth, windowHeight, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (!mainwindow) /* Agar yaratib bo'lmasa */
        sdldie("Oynani yaratishda xatolik");
 
    /* OpenGL oynasini yaratish */
    maincontext = SDL_GL_CreateContext(mainwindow);
 
	//oyna o'lchamini berish
	//glOrtho(0, 10, 15, 0, -1, 1);
	glViewport(0, 0, windowWidth, windowHeight);

	glLoadIdentity();
	gluPerspective(45.0f, windowWidth / (float)windowHeight, 0.01f, 900.0f);
	
	gluLookAt(150, 150, 150, 0, 0, 10, 0, 0, 1);

	/* Bufferni tozalash rangi */
	glClearColor ( 0.0f, 0.0f, 0.0f, 1.0 );

	SDL_Event e;

	//game loop
	while( isRunning )
	{
		//klaviatura bosilganligini tekshiradi
		if (SDL_PollEvent(&e))
		{
			if (e.type == SDL_KEYDOWN) 
			{
				switch(e.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						isRunning = false;
						break;
				}
			}
		}

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		draw_coords();
		draw_matrix_point(point);

		rotate(&point, 1, 0, 0, 10);

		SDL_Delay(10); //10 ms ga pausa qilish

		SDL_GL_SwapWindow(mainwindow);
	}

	//tozalash va chiqish
    SDL_GL_DeleteContext(maincontext);
    SDL_DestroyWindow(mainwindow);
    SDL_Quit();
 

	return 0;
}


Natija (EXE ko'chirish):



Sizga vaxima bo'lib ko'rinayotgan kodda aslida hech narsa yozilmagan desayam bo'ladi. Keyingi maqolamda huddi shu natijani OpenGL ni funksiyalaridan foydalanib qilamiz.

Нет комментариев