계속 밍기적 밍기적 미루고 있던 그래픽스 숙제를 드디어 해내다!
하루만에 한거라 좀 허접한 면이 있지만.
그래도 할건 다 했다.
세완이형의 도움이 절대적으로 컸고,
이해해야 하는 부분이 좀 더 많다.
아무튼간.
소스와 결과물은 다음과 같다.
OpenGl의 각종 함수에 대한 정리도 같이 해 놓는다!
Result
'고' 자를 그리는 숙제였는데, 어떤 선을 긋는게 아니라.
점을 쭉 찍어서 그리는게 포인트이다!
Opengl을 사용해서, 그리는 숙제다!
사용되는 알고리즘으로는 Midpoint 알고리즘 (원 그릴 때,)
직선 알고리즘으로는 Breham 알고리즘 (맞나?;) 암튼 고거다!
키보드 입력을 받으면, 저기 고자 에서 아래 'ㅗ' 받침중 튀어 나온 부분만,
크림슨 색으로 칠해지는게 포인트다.
Soruce Code
/*These part is included file*/
#include <windows.h>
#include <gl/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
void myReshape (int w, int h) {
glLoadIdentity (); // This function can reset screen
glMatrixMode(GL_PROJECTION); // This fuction can make 3D to 2D
glViewport (0, 0, w, h); // 중요한 부분인데, 우리가 그리는 부분 즉, 윈도우즈의 크기가
// w 와 h 에 자동으로 반영된다. 이 경우, w,h와 아래줄에서 //사용한 좌표축과의 대응 비율에 따라, 확대가 되기도 하고 축소가 //되어 보이기도 하니 조심! 많이 헷갈리게 된다! 모두 같으면 1:1
gluOrtho2D (0.0, 300.0, 0.0, 300.0); // I used x-width is 300 and y-width is 300
}
// This class is point.
class scrPt {
public:
GLint x, y;
};
// This function can save currently color by using point x,y.
void setPixel (GLint x, GLint y)
{
glBegin (GL_POINTS);
glVertex2i (x, y);
glEnd ( );
}
//원을 그리는 알고리즘이다
// This function can draw circle by using midpoint algorithm
void circleMidpoint (scrPt circCtr, GLint radius,int location)
{
scrPt circPt;
GLint p = 1 - radius; // Initial value of midpoint parameter.
circPt.x = 0; // Set coordinates for top point of circle.
circPt.y = radius;
void circlePlotPoints (scrPt, scrPt, int);
/* Plot the initial point in each circle quadrant. */
circlePlotPoints (circCtr, circPt, location);
/* Calculate next points and plot in each octant. */
while (circPt.x < circPt.y) {
circPt.x++;
if (p < 0)
p += 2 * circPt.x + 1;
else {
circPt.y--;
p += 2 * (circPt.x - circPt.y) + 1;
}
circlePlotPoints (circCtr, circPt, location);
}
}
void circlePlotPoints (scrPt circCtr, scrPt circPt, int location)
{
switch(location) {
case 1 : // This is x>0, y>0
setPixel (circCtr.x + circPt.x, circCtr.y + circPt.y);
setPixel (circCtr.x + circPt.y, circCtr.y + circPt.x);
break;
case 2 : // This is x<0, y>0
setPixel (circCtr.x - circPt.x, circCtr.y + circPt.y);
setPixel (circCtr.x - circPt.y, circCtr.y + circPt.x);
break;
case 3 : // This is x<0, y<0
setPixel (circCtr.x - circPt.y, circCtr.y - circPt.x);
setPixel (circCtr.x - circPt.x, circCtr.y - circPt.y);
break;
case 4 : // This is x>0, y<0
setPixel (circCtr.x + circPt.y, circCtr.y - circPt.x);
setPixel (circCtr.x + circPt.x, circCtr.y - circPt.y);
break;
default : // This case can draw perfect circle
setPixel (circCtr.x + circPt.x, circCtr.y + circPt.y);
setPixel (circCtr.x - circPt.x, circCtr.y + circPt.y);
setPixel (circCtr.x + circPt.x, circCtr.y - circPt.y);
setPixel (circCtr.x - circPt.x, circCtr.y - circPt.y);
setPixel (circCtr.x + circPt.y, circCtr.y + circPt.x);
setPixel (circCtr.x - circPt.y, circCtr.y + circPt.x);
setPixel (circCtr.x + circPt.y, circCtr.y - circPt.x);
setPixel (circCtr.x - circPt.y, circCtr.y - circPt.x);
break;
}
}
/* Bresenham line-drawing procedure for |m| < 1.0. */
void lineBres (int x0, int y0, int xEnd, int yEnd)
{
int dx = abs(xEnd - x0), dy = abs(yEnd - y0); //abs는 정수 절대값 구하는 함수
// fabs는 실수
int p = 2 * dy - dx;
int twoDy = 2 * dy, twoDyMinusDx = 2 * (dy - dx);
int x, y;
/* Determine which endpoint to use as start position. */
if (x0 > xEnd) {
x = xEnd;
y = yEnd;
xEnd = x0;
}
else {
x = x0;
y = y0;
}
setPixel (x, y);
while (x < xEnd) {
x++;
if (p < 0)
p += twoDy;
else {
if(y0<yEnd) {
y++;
}
else {
y--; // I must use this code. Because this part can draw case of m<0.
}
p += twoDyMinusDx;
}
setPixel (x, y);
}
// I must draw line when x0 eqaul xEnd. So,I add this part code.
if(x0=xEnd) {
while (y < yEnd) {
y++;
setPixel (x, y);
}
}
}
void display (void) {
//midpoint define
scrPt cntr1;
scrPt cntr2;
scrPt cntr3;
scrPt cntr4;
//raudis define
cntr1.x = 20;
cntr1.y = 35;
cntr2.x = 110;
cntr2.y = 35;
cntr3.x = 95;
cntr3.y = 135;
cntr4.x = 35;
cntr4.y = 135;
glClear (GL_COLOR_BUFFER_BIT);
//set color
glColor3f (1.0, 1.0, 1.0);
/*width*/
lineBres(35, 150, 95, 150);
lineBres(35, 120, 80, 120);
lineBres(20, 50, 50, 50);
lineBres(80, 50, 110, 50);
lineBres(20, 20, 110, 20);
/*Height*/
lineBres(50, 50, 50, 80);
lineBres(80, 50, 80, 70);
lineBres(80, 85, 80, 120);
lineBres(110, 75, 110, 135);
/*Line*/
lineBres(50, 80, 80, 70);
lineBres(80, 85, 110, 75);
/*draw part partly circle*/
circleMidpoint(cntr1, 15, 2);
circleMidpoint(cntr1, 15, 3);
circleMidpoint(cntr2, 15, 1);
circleMidpoint(cntr2, 15, 4);
circleMidpoint(cntr3, 15, 1);
circleMidpoint(cntr4, 15, 2);
circleMidpoint(cntr4, 15, 3);
glFlush ();
}
//This function operate when there is input of keyboard.
void refresh(unsigned char key, int x, int y) {
int flag = 0; // This flag can check white line point
int i = 0;
int pixels2[1000]; // This point can save color frame 배열 선언 부분
glReadPixels(50, 50, 31, 30, GL_RGBA, GL_UNSIGNED_BYTE, &pixels2[0]); /* This fuction can get frame's information and give pixels array information. 이 함수가 프레임에서 받아다 읽어서 pixels2 배열에 넣어 준다. 나는 RGBA 형으로, 50,50 좌표부터 31, 30 크기의 네모난 프레임을 읽어서 부호 없는 byte 타입으로 배열에 저장한 것이다. 위의 코드는 다음과 같이 수정해서 쓸수도 있다.*/
//int *pixels;
//pixels = (int *)malloc(sizeof(int)*1000);
//glReadPixels(50, 50, 30, 30, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
//This part can seperate inter point and outer point
//I use method to check point number of wihte.
//If there is more two wihte point, There are not more crimson change
for(;i<1000;i++) {
if(pixels2[i]==0) {
glColor3f(220.0/255,20.0/255,60.0/255.0); // Thhs is crimson red color 색 셋팅하는 함수
// 3개의 float 수로 표현 dc143c 16진수 크림슨색
if(flag<=2) {
setPixel(50+i%31,50+i/31); // Pixel을 채운다 프레임에 정보로!
}
}
else {
if(i%31==0) {
flag = 0;
}
flag += 1;
}
}
glFlush(); // 이것은 현재 프레임에 있는 정보를 그리라는 것으로 프레임 정보는 유지
// 혹시 스왑 버퍼라는 함수는, 함수를 그리고 비우라는 것임
}
//This part is main function of program
void main (int argc, char **argv)
{
// 보통 플랫폼에서 독립된 루틴을 주는 것을 glut라고 하는데 glut 함수는 앞에 전부 glut 함수가
// 들어 있다.
glutInit (&argc, argv); // 초기화 시키는 함수
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // 현재 사용할 버퍼를 한개를 사용할 //것인지, 2개를 사용할 것인지를 선택 //하고 타입을 RGB로 할 것인지 선 //택 : 상수 인자로 선언되어 있다.
//그려질 윈도우즈 콘솔창 조정 부분
glutInitWindowPosition(200,200);
glutInitWindowSize(300,300);
glutCreateWindow ("First homework 2003210044 Kim hyeong cheol"); // 창을 생성
glutReshapeFunc (myReshape);//현재 창을 새로 셋팅하고 좌표계 셋팅
glutDisplayFunc (display);//디스플레이를 할 함수를 호출해서 창에 넘겨줌
glutKeyboardFunc(refresh);//키보드 입력이 들어 왔을 때 반응하는 함수 등록
glutMainLoop();//창을 보이게 하고 무한 루프 돌게 함
//이건 C의 팁인데, 그냥 함수의 이름을 주면 주소 값으로 들어가고, 자동으로 인자값이 default 되어 있으면 들어간다. 예를 들면, myReshape 도 함수지만, default값이 들어가고 호출된다.
}
참고 소스 : C에서 memset 이란 함수로 배열이나, 포인터를 초기화를 시킬 수 있다.
참고하면 좋을 블로그
http://www.gisdeveloper.co.kr/category/OpenGL?page=2
오픈 GL의 다양한 자료가 있다.
Tip
한가지 팁 : visual studio 2005 로 컴파일 하다가
눈에 띄는 단어가 있어서 정리해 둔다.
컴파일 과정 중에 매니페스토 라는 단어가 눈에 띄어서,
뭔가 하고 곰곰히 찾아 보니까,
매니페스토란 선거에서 사용되는 지키겠다. 뭔가 지키기 위한 포석 같은걸 의미한다고 한다.
즉, 표준화나, 공약, 기준점 제시등을 의미하는 듯 하다.