• 북마크
  • 추가메뉴
어디로 앱에서 쉽고 간편하게!
애플 중고 거래 전문 플랫폼
오늘 하루 보지 않기
KMUG 케이머그

소프트웨어

[App 개발] NeHe Lesson 21

본문

늦었습니다. ^^ 이번에는 내용도 많고, 간단하긴 하지만 그래도 게임 제작이고, 원래가 윈도우용으로 제작된 소스를 이식해야 하는 것이라 빼먹은 부분도 많고, 그래도 대충 돌아가게끔 맞춰놓긴 했습니다만... 어쨌든 즐겨 주십시오. ^^

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

저의 21번째 OpenGL 강의에 잘 오셨습니다. 이번 강의에서 다루어질 주제는 아주 어려웠습니다. 지금까지 기초적인 것들만 해 오느라 지루하셨을 줄 압니다. 여러분들은 3D 물체, 다중 텍스쳐 등과 같은 쓸만한 것들을 열심히 해 오시느라 힘드실 겁니다. 그런데 죄송합니다만, 저는 여러분들에게 꾸준히 계속 공부하시라고 말씀드리고 싶습니다. 한 번 발을 떼고 나면 멀어진 관심을 회복하고 다시 돌아오는 것이 쉽지 않습니다. 따라서 여러분이 꾸준히 할 수 있도록 밀어드리고자 합니다.

여러분이 발길을 끊을까봐서, 이 강의에 대해서 먼저 몇 가지 말씀드리겠습니다. 지금까지 제 강의는 다각형, 사각형, 삼각형들을 이용해 왔습니다. 그래서 강의를 선분을 이용해서 만드는 것이 좋을 것 같아서 그렇게 결정했습니다. 그런데 선분 강의를 만들면서 그만두어야겠다고 결정했습니다. 강의 자체는 괜찮았습니다만, 따분했거든요. 선분을 이용하는 것은 중요하지만, 선분은 중요합니다, 그러나 선분 만들기를 재미있게 만드는 방법이 있을 것이라 생각했습니다. 저는 이메일을 읽고, 게시판의 글들을 검색하고, 여러분의 강의 질문들을 답변해 왔는데, 여러 질문들 중에서 저에게 다가오는 몇 가지 질문들이 있었습니다. 따라서, 저는 다중 강의를 하기로 결심했습니다.

이번 강의에서 배울 것은, 선분, 안티 알리아싱, 정사영법, 타이밍, 기본 사운드 효과, 그리고 간단한 게임 로직 등입니다. 이정도면 모든 사람들을 기쁘게 할 수 있기를 바랍니다. 이 강의를 코딩하는 데 이틀이 걸렸고, HTML 을 작성하는데 2주가 걸렸습니다. 노력의 결과를 즐겨주세요.

강의 마지막에 가서 여러분은 간단한 ‘amidar’ 형태의 게임을 만들게 될 것입니다. 게임의 목적은 적들을 피해서 격자를 채워 나가는 일입니다. 이 게임은 난이도, 판, 주인공수, 사운드, 그리고 어려운 판에서 도움을 받을 수 있는 숨은 아이템 등이 있습니다. 물론 이 게임은 팬티엄 2 에 부두 2 카드에서도 동작합니다만, 부드러운 애니메이션을 위해서 좀 더 빠른 컴퓨터가 좋습니다.

이 코드는 강의 1 번 코드로부터 시작했습니다. 먼저 필요한 헤더 파일을 첨부하는 것으로 시작합니다. stdio.h는 파일 입출력을 위해서 필요하고 stdarg.h는 판 수, 현재 점수 등, 화면에 변수를 출력하는 데에 쓰입니다.


#include
#include

#include
#include
#include


이제 논리 변수를 선언합니다. 변수 vline 은 게임의 격자를 구성하는 121개의 수직선의 위치를 기록합니다. 변수 hline 은 게임의 격자를 구성하는 121개의 수평선의 위치를 기록합니다. 그리고 변수 ap 는 키보드 A 가 눌렸는지를 검사합니다.

변수 filled 가 FALSE 라면 격자가 아직 채워지지 않은 것이고 TRUE 라면 채워진 것입니다. 변수 gameover 는 당연하죠. 만일 gameover 가 TRUE 라면 게임 끝이고, 그렇지 않으면 아직 게임중입니다. 변수 anti 는 안티 알리아싱을 기록합니다. 만일 anti 가 TRUE 이면 물체의 안티 알리아싱은 ON 이고, 그렇지 않으면 OFF 입니다. 변수 active 와 fullscreen 은 프로그램이 최소화되었는지, 그리고 전체 화면 모드인지 윈도우 모드인지를 기록합니다.


bool vline[11][10];
bool hline[10][11];
bool ap;
bool filled;
bool gameover;
bool anti=TRUE;
bool active=TRUE;
bool fullscreen=TRUE;


이제 정수형 변수를 선언합니다. 변수 loop1과 loop2 는 격자의 접선을 검사할 때 쓰입니다. 만약 적이 나에게 맞아서 물체에게 격자 위 무작위의 위치에 놓는다고 합시다. 프로그램에서 loop1 / loop2 를 사용하는 것을 보게 될 것입니다. 변수 delay 는 적의 움직임을 둔화시키는 데 쓰이는 카운터 변수입니다. 만일 delay 가 어떤 값보다 클 때 적이 움직이고 delay 는 0 으로 바뀝니다.

변수 adjust 는 아주 특별합니다. 이 프로그램에는 타이머가 있지만 타이머는 단지 컴퓨터가 너무 빠른지를 검사해서, 그럴 경우 딜레이를 만들어서 컴퓨터를 느리게 만듭니다. 제 GeForce 카드에서는 너무 부드럽고 아주 빠르게 동작합니다. 이 프로그램을 팬3/450 에 부두 3500TV 에서 실험한 다음 이 프로그램이 아주 느리다는 것을 알았습니다. 문제는 제 타이밍 코드는 게임 속도를 느리게 만들 뿐, 빠르게 하지는 못합니다. 그래서 저는 다른 변수 adjust 를 만들었습니다. 변수 adjust 는 0부터 5까지의 값을 갖습니다. 게임에서 물체들은 adjust 의 값에 따라 다른 속도로 움직이게 됩니다. 값이 작으면 부드럽게 움직이고, 값이 크면 움직임이 빨라집니다. (3을 넘으면 잽싸게 움직이죠) 이 방법이 느린 시스템에서 이 게임을 움직이게 할 수 있는 가장 쉬운 방법이었습니다. 문제는, 물체가 얼마나 빠르게 움직이건 게임은 제가 생각하는 것보다 빠르게 움직이지 못합니다. 따라서 adjust 값을 3 으로 놓는 것이 속도에 관계없이 가장 안전한 방법입니다.

변수 lives 는 5 로 정의되어 주인공 댓수는 5 대입니다. 변수 level 은 내부 변수입니다. 게임에서 이 변수를 이용하여 난이도를 알 수 있습니다. 이것은 화면에 보이는 레벨하고는 다른 것입니다. 변수 level2 는 변수 level 과 같은 값을 가지고 시작하지만 사용자의 실력에 따라 무한대로 증가할 수 있습니다. 만약 level 3 에서 죽으면 변수 level 은 3 에서 증가를 멈출 것입니다. 변수 level 은 게임의 난이도에 쓰이는 내부 변수입니다. 변수 stage 는 현재 게임의 판을 기록하는 변수입니다.


int loop1;
int loop2;
int delay;
int adjust=3;
int lives=5;
int level=1;
int level2=level;
int stage=1;


이제 게임에서 쓰일 물체의 상태를 기록하는 구조체를 만듭니다. 먼저 세밀한 x 위치 (fx) 와 y 위치 (fy) 를 가집니다. 이 변수들은 주인공과 적을 격자 위에서 수 픽셀씩 움직이게 해서, 부드럽게 움직이는 물체를 만들어줍니다.

그 다음에 x 와 y 입니다. 주인공이 어떤 교차로에 와 있는지를 기록하는 변수입니다. 이 게임에는 11개의 가로줄과 11개의 세로줄이 있습니다. 따라서 x 와 y 는 0 부터 10 까지의 숫자를 갖습니다. 우리가 세밀한 값을 가져야 하는 이유는, 물체가 겨우 좌우로 11 점, 위아래로 11 점씩밖에 움직이지 못한다면 주인공은 화면에서 띄엄띄엄 다니게 될 것입니다.

마지막 변수 spin 은 물체를 z 축을 중심으로 회전하는 데 쓰입니다.


struct object
{
int fx, fy;
int x, y;
float spin;
};


이제 우리는 주인공과 적과 특수 아이템에 사용할 수 있는 구조체를 만들었습니다. 방금 만든 구조체의 특성을 받아서 이용할 수 있습니다.

다음 첫 번째 줄은 주인공의 구조체입니다. 기본적으로 우리는 주인공 구조체에 fx, fy, x, y, spin 을 부여했습니다. 이렇게 함으로써 우리는 주인공의 x 위치를 player.x 를 참조함으로써 알 수 있습니다. 우리는 player.spin 에 숫자를 더함으로써 주인공을 회전시킬 수 있습니다.

두 번째 줄은 약간 다릅니다. 우리는 화면에 동시에 아홉 마리의 적을 만들 것이므로, 적 하나마다 변수 하나씩을 만들어 줘야 합니다. 우리는 적 아홉 마리를 위한 배열을 만들었습니다. 첫 번째 적의 x 위치는 enemy[0].x 가 되고, 두 번째 적은 enemy[1].x, 이렇게 됩니다.

마지막 줄은 특수 아이템을 위한 구조체입니다. 특수 아이템은 화면에 종종 나타나는 모래시계입니다. 우리는 모래시계의 x 와 y 위치를 알아야 하지만, 모래시계는 움직이지 않습니다. 따라서 우리는 세밀한 위치를 알아야 할 필요가 없습니다. 대신에 우리는 변수 fx 와 fy 를 뒤에서 다른 용도로 사용할 것입니다.


struct object player;
struct object enemy[9];
struct object hourglass;


이제 타이머 구조체를 만들겠습니다. 이렇게 함으로써 타이머 변수를 쉽게 추적할 수 있고 그래서 우리가 이 변수를 타이머 변수라고 말할 수 있습니다.

먼저 frequency 라는 이름의 64비트 정수를 만듭니다. 이 변수는 타이머의 주파수를 기록합니다. 처음 이 프로그램을 만들 때 이 변수를 만드는 것을 잊었습니다. 저는 한 컴퓨터의 주파수가 다른 컴퓨터와 맞지 않는다는 것을 인식하지 못했습니다. 저의 큰 실수였죠. 저희 집에 있던 컴퓨터 세 대에서는 잘 돌았습니다만, 친구들 집에서 실행해 보았더니 게임 속도가 너무 빨랐던 것입니다. 주파수란 기본적으로 얼마나 빨리 클럭이 변경되는가입니다. 알아야 할 중요한 내용이죠.

변수 resolution 은 1밀리초동안 몇 스탭인가를 기록합니다.

변수 mm_timer_start 와 mm_timer_elapsed 는 타이머의 시작 시간과 타이머가 시작된지 얼마나 시간이 지났는지의 값을 갖고 있습니다. 이 두 변수는 컴퓨터의 performance counter가 없는 경우에 사용됩니다. 시간이 크게 중요하지 않은 이런 게임에서 사용하기에 나쁘지 않은 방법입니다.

변수 performance_timer 는 TRUE나 FALSE 값을 가집니다. 만약 프로그램이 performance counter 를 찾았으면 변수 performance_timer 는 TRUE가 되고 모든 타이밍 작업은 performance counter 를 이용하게 됩니다. (멀티미디어 타이머보다 훨씬 정확합니다) 만약 performance counter 를 못찾으면 performance_timer 는 FALSE 가 되고 멀티미디어 타이머가 타이밍에 사용됩니다.

마지막 변수 두 개는 performance counter 의 시작 시간과 카운터가 시작된지 얼마나 시간이 흘렀는지를 기록하는 64비트 정수형 변수입니다.

구조체 밑부분에 보시는대로 이 구조체의 이름은 timer 입니다. 만약 타이머 주파수를 알고 싶으시면 이제 timer.frequency 를 보십시오.


struct
{
__int64 frequency;
float resolution;
unsigned long mm_timer_start;
unsigned long mm_timer_elapsed;
bool performance_timer;
__int64 performance_timer_start;
__int64 performance_timer_elapsed;
} timer;


다음은 스피드 테이블입니다. 게임 내의 물체들은 조절되는 값에 의해서 다른 속도로 움직이게 됩니다. 만약 adjust 가 0 이면 물체들은 한 번에 한 픽셀씩 움직입니다. 만약 adjust 가 5 라면 물체들은 한 번에 20픽셀씩 움직입니다. 따라서 adjust 의 값을 높임으로써 물체의 속도가 빨라지게 되고, 느린 컴퓨터에서 게임을 빠르게 만들 수 있습니다. 그러나 adjust 값이 높아지면 게임 움직임이 끊어져 보이게 됩니다.

기본적으로 steps[] 는 단순한 보기표 입니다. 만약 adjust 가 3 이라면 steps[]의 세 번째 위치에 기록된 숫자를 갖고 오게 됩니다. 0 번 장소에는 1 이 있고, 1번 장소에는 2, 2번 장소에는 4, 3번 장소에는 5가 기록되어 있습니다. 만약 adjust 가 3 이었다면 물체들은 한 번에 5픽셀씩 움직일 것입니다. 이해 되시죠?


int steps[6]={ 1, 2, 4, 5, 10, 20 };


이제 텍스쳐 두 개를 기록할 장소를 마련합니다. 배경 씬과 글꼴 텍스쳐 비트맵입니다. 다음에는 변수 base 를 설정하여 옛날 글꼴 예제에서 했던 것과 마찬가지로 글꼴 출력 리스트를 기록할 것입니다.


GLuint texture[2];
GLuint base;


이제 재미있는 부분입니다. 다음은 타이머의 초기화입니다. 프로그램에서는 컴퓨터에 performance counter(아주 정확한 카운터) 가 있는지를 검사합니다. 만약 performance counter 가 없으면 컴퓨터는 멀티미디어 타이머를 사용할 것입니다. 이 코드는 말씀드린 대로 재사용할 수 있습니다.

먼저 타이머 변수들을 0으로 만드는 것으로 시작합니다. 이것은 타이머 구조체의 모든 변수를 0으로 만드는 일입니다. 그 다음 performance counter 가 없는지 검사합니다. 연산자 ! 는 NOT 을 뜻합니다. 카운터가 있다면 frequency 는 timer.frequency 에 저장됩니다.

만일 performance counter 가 없다면 { } 사이에 있는 코드가 동작합니다. 첫 번째 줄은 변수 timer.performance_timer 를 FALSE 로 놓습니다. 컴퓨터에 performance counter 가 없다는 뜻입니다. 다음은 멀티미디어 타이머의 시작 값을 timeGetTime()으로 얻습니다. timer.resolution 을 0.001f 로 놓고 timer.frequency 를 1000으로 놓습니다. 시간이 아직 지나지 않았으므로 경과된 시간과 시작 시간을 동일하게 놓습니다.


void TimerInit(void)
{
memset(&timer, 0, sizeof(timer));

if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency))
{
timer.performance_timer = FALSE;
timer.mm_timer_start = timeGetTime();
timer.resolution = 1.0f/1000.0f;
timer.frequency = 1000;
timer.mm_timer_elapsed = timer.mm_timer_start;
}


만약 performance counter 가 있다면 다음 코드가 실행됩니다. 첫 번째 줄은 performance counter 의 시작 값을 얻어서 timer.performance_timer_start 에 저장합니다. 그 다음 timer.performance_timer 를 TRUE 로 놓아서 컴퓨터에 performance counter 가 있음을 알립니다. 위의 performance counter 가 있는지를 검사하는 코드에서 얻은 주파수를 이용해서 타이머의 해상도를 계산합니다. 해상도는 1 나누기 주파수입니다. 마지막으로 시작 시간과 경과 시간을 동일하게 만듭니다.

Performance counter 와 멀티미디어 타이머의 시작 시간과 경과 시간 변수를 여기서는 변수를 공유하지 않고 따로 만들었습니다만, 어쨌든 동작하는 데에는 문제가 없습니다.


else
{
QueryPerformanceCounter((LARGE_INTEGER *) &timer.performance_timer_start);
timer.performance_timer = TRUE;
timer.resolution = (float) (((double)1.0f)/((double)timer.frequency));
timer.performance_timer_elapsed = timer.performance_timer_start;
}
}


지금까지 타이머를 세팅했습니다. 이번에는 타이머를 읽어서 얼마나 많은 시간이 흘렀는지 밀리초 단위로 리턴하는 코드입니다.

먼저 해야 할 일은 time 이라고 하는 64비트 변수를 선언하는 일입니다. 이 변수는 현재의 카운터 값을 얻는 데 쓰입니다. 다음은 performance counter 가 있는지를 검사해서, 있을 경우 timer.performance_timer 는 TRUE 가 되고 그 다음 코드가 실행됩니다.

대괄호 { } 속의 첫 번째 줄은 카운터 값을 받아서 time 이라고 만들어 둔 변수에 저장합니다. 다음 줄은 방금 얻은 시간을 구합니다. 변수 time 에서 타이머를 초기화할 때 얻은 시작 시간을 뺍니다. 이렇게 하면 타이머 값은 거의 0에서부터 시작됩니다. 다음은 위의 결과에 resolution 을 곱하여 얼마나 많은 시간이 흘렀는지를 검사합니다. 마지막으로 결과값에 1000을 곱하여 몇 밀리초가 흘렀는지를 알 수 있게 합니다. 계산이 끝나고 나면 그 결과가 이 함수를 호출한 루틴으로 전달됩니다. 결과값은 정확도를 높이기 위해서 부동소숫점을 사용합니다.

만약 performance counter 를 사용하지 않는다면 else 구문 이후의 코드가 실행됩니다. 하는 일은 거의 비슷합니다. 현재 시간을 timeGetTime() 으로 받아서 시작 카운터 값을 뺍니다. 그리고 resolution 과 곱하고 이 결과를 1000으로 곱하여 초 단위에서 밀리초 단위로 변환합니다.


float TimerGetTime()
{
__int64 time;

if (timer.performance_timer)
{
QueryPerformanceCounter((LARGE_INTEGER *) &time);
return ( (float) ( time - timer.performance_timer_start) * timer.resolution)*1000.0f;
}
else
{
return( (float) ( timeGetTime() - timer.mm_timer_start) * timer.resolution)*1000.0f;
}
}


다음은 주인공을 화면 왼쪽 위로 초기화하고 적들을 무작위로 흩어놓는 것입니다.

화면 왼쪽 위는 x 축으로 0, y 축으로 0입니다. 변수 player.x 를 0 으로 놓으면 주인공을 화면 맨 왼쪽으로 놓을 수 있습니다. 변수 player.y 를 0 으로 놓으면 주인공을 화면 위로 놓을 수 있습니다.

세밀한 위치값은 현재 주인공 위치와 맞아야 합니다. 그렇지 않으면 주인공은 화면 왼쪽 위의 정확한 위치의 아무 위치에서나 움직이기 시작하게 됩니다. 주인공이 그 쪽에서 나타나서 움직이는 것은 좋지 않으므로 세밀한 위치도 0으로 놓습니다.


void ResetObjects(void)
{
player.x=0;
player.y=0;
player.fx=0;
player.fy=0;


다음은 적에게 무작위의 위치를 부여합니다. 적의 숫자는 현재 판 곱하기 현재 (내부) 레벨을 곱한 값과 같습니다. 레벨의 최대값은 3이고, 판 당 레벨의 최대값은 3입니다. 따라서 화면에는 최대 9 마리의 적이 출연할 수 있습니다.

보이는 적들이 새로운 위치에 출연하게 하기 위해서 모든 보이는 적을 루프로 (stage 곱하기 level) 돌립니다. 각 적의 x 위치를 5 더하기 0부터 5까지의 난수값으로 놓습니다. (rand()함수의 최대값은 항상 지정한 값 빼기 1 입니다) 따라서 적은 격저 위 5부터 10 사이에 놓이게 됩니다. 그 다음은 적의 y 축 값을 0부터 10 사이의 난수로 놓습니다.

적이 옛날 위치에서 새 난수 위치로 움직이게 하지 않기 위해서 세밀한 위치 x (fx) 와 y (fy) 값을 실제 x 와 y 값 곱하기 화면의 각 격자의 넓이와 높이 값으로 놓습니다. 각 격자는 넓이가 60이고 높이가 40입니다.


for (loop1=0; loop1<(stage*level); loop1++)
{
enemy[loop1].x=5+rand()%6;
enemy[loop1].y=rand()%11;
enemy[loop1].fx=enemy[loop1].x*60;
enemy[loop1].fy=enemy[loop1].y*40;
}
}


AUX_RGBImageRec 코드는 변동이 없으니 넘어갑니다. LoadGLTexture() 에서는 텍스쳐 두 개를 읽어들입니다. 첫 번째는 글꼴 비트맵 (Font.bmp) 이고 그 다음은 배경 이미지 (Image.bmp) 입니다. 우리는 게임에서 사용하기 위해 이 두 이미지를 텍스쳐로 변환할 것입니다. 텍스쳐를 모두 만들고 난 다음 비트맵 정보를 지워서 메모리를 정리합니다. 새로운 것은 없습니다. 지금까지 다른 강의를 읽어오셨다면 이 코드를 이해하는 데 문제가 없으실 것입니다.


int LoadGLTextures()
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[2];
memset(TextureImage,0,sizeof(void *)*2);

if ((TextureImage[0]=LoadBMP("Data/Font.bmp")) &&
(TextureImage[1]=LoadBMP("Data/Image.bmp")))
{
Status=TRUE;

glGenTextures(2, &texture[0]);

for (loop1=0; loop1<2; loop1++)
{
glBindTexture(GL_TEXTURE_2D, texture[loop1]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop1]->sizeX, TextureImage[loop1]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop1]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}

for (loop1=0; loop1<2; loop1++)
{
if (TextureImage[loop1])
{
if (TextureImage[loop1]->data)
{
free(TextureImage[loop1]->data);
}
free(TextureImage[loop1]);
}
}
}
return Status;
}


다음은 글꼴의 출력 리스트를 만듭니다. 비트맵 텍스쳐 글꼴 만들기 강의는 이미 했습니다. 코드에서 하는 일은 Font.bmp 이미지를 16 x 16 조각 (256글자) 로 나누는 일입니다. 각 16 x 16 조각이 한 글자입니다. y축이 양수가 되면 위를 향하지 않고 아래를 향하기 때문에 y 축 값을 1.0f 에서 빼야 합니다. 그렇지 않으면 글자들이 거꾸로 됩니다. 이 코드가 이해가 안 되시면 비트맵 텍스쳐 글꼴 강의로 돌아가셔서 읽어보십시오.


GLvoid BuildFont(GLvoid)
{
base=glGenLists(256);
glBindTexture(GL_TEXTURE_2D, texture[0]);
for (loop1=0; loop1<256; loop1++)
{
float cx=float(loop1%16)/16.0f;
float cy=float(loop1/16)/16.0f;

glNewList(base+loop1,GL_COMPILE);
glBegin(GL_QUADS);
glTexCoord2f(cx,1.0f-cy-0.0625f);
glVertex2d(0,16);
glTexCoord2f(cx+0.0625f,1.0f-cy-0.0625f);
glVertex2i(16,16);
glTexCoord2f(cx+0.0625f,1.0f-cy);
glVertex2i(16,0);
glTexCoord2f(cx,1.0f-cy);
glVertex2i(0,0);
glEnd();
glTranslated(15,0,0);
glEndList();
}
}


글꼴을 다 사용하고 나면 메모리에서 지워 버리는 것이 좋습니다. 그래서 저는 아래의 코드를 첨가했습니다. 다시 말씀드리지만, 새로운 것은 없습니다.


GLvoid KillFont(GLvoid)
{
glDeleteLists(base,256);
}


glPrint() 함수는 큰 변동이 없습니다. 지난 비트맵 글꼴 텍스쳐 강의와 한 가지 차이가 있는것은 변수값을 출력하는 기능을 첨가한 것입니다. 여기에 함수 전부를 올려놓은 이유는 여러분이 바뀐 부분을 쉽게 보시도록 하기 위해서입니다. 출력 명령은 여러분이 지정한 x, y 지점에 글자를 놓을 것입니다. 여러분은 두 개의 글꼴 셋에서 하나를 고를 수 있고 변수의 값을 화면에 출력할 수 있습니다. 이렇게 해서 현재 레벨과 판을 화면에 출력할 수 있게 됩니다.

제가 여기서 텍스쳐 매핑을 켜고 뷰를 초기화하고 지정된 x, y 위치로 이동한 것을 잘 보십시오. 그리고 만일 글꼴 셋 0이 선택되면 글꼴의 넓이가 1.5배, 높이가 2배로 확대되도록 한 것도 잘 보십시오. 이렇게 해서 게임 제목을 큰 글자로 쓸 수 있게 했습니다. 글자가 그려지고 난 다음에는 텍스쳐 매핑을 끕니다.


GLvoid glPrint(GLint x, GLint y, int set, const char *fmt, ...)
{
char text[256];
va_list ap;

if (fmt == NULL)
return;

va_start(ap, fmt);
vsprintf(text, fmt, ap);
va_end(ap);

if (set>1)
{
set=1;
}
glEnable(GL_TEXTURE_2D);
glLoadIdentity();
glTranslated(x,y,0);
glListBase(base-32+(128*set));

if (set==0)
{
glScalef(1.5f,2.0f,1.0f);
}

glCallLists(strlen(text),GL_UNSIGNED_BYTE, text);
glDisable(GL_TEXTURE_2D);
}


화면 크기 조정 코드는 새것입니다. 이번 강의에서는 투시도법을 사용하지 않고 정사영법을 사용합니다. 물체가 관찰자로부터 멀리 떨어지더라도 크기가 작게 보이지 않는다는 뜻입니다. 이번 강의에서는 z 축이 거의 쓸모가 없습니다.

먼저 뷰포트를 설정하는 것으로 시작합니다. 투시도법을 설정하던 것과 같은 방법으로 수행합니다. 우리는 뷰포트를 윈도우의 넓이와 동일하게 만듭니다.

그 다음 프로젝션 매트릭스 (영화 프로젝터처럼, 어떻게 화면에 출력할 것인가의 정보) 를 선택하고 초기화합니다.

초기화 다음 정사영 뷰를 설정합니다. 이 명령은 자세히 설명하겠습니다.

첫 번째 인수 0.0f 는 화면 왼쪽 끝을 나타내는 값입니다. 여러분은 실제 픽셀값을 어떻게 사용하는지 알고 싶으실 것입니다. 따라서 저는 음수값을 사용하지 않고 이 값을 0으로 만들었습니다. 두 번재 인수는 화면의 오른쪽 값입니다. 우리 윈도우가 640x480 이라면 width 에 들어있는 값은 640이 됩니다. 그래서 화면 오른쪽 값은 실질적으로 640이 됩니다. 따라서 화면의 x 축은 0부터 639의 값 (640 픽셀) 이 됩니다.

세 번째 인수 (height) 는 일반적으로 y 축의 값 (화면의 아래쪽) 으로서 일반적으로 음수를 가집니다. 그러나 우리는 실제 픽셀 값을 쓰기를 원하므로 음수가 되면 안됩니다. 대신에 화면 아래쪽을 윈도우의 height 값과 같이 놓습니다. 우리 윈도우 크기가 640x480이므로 height는 480이 됩니다. 그래서 화면 맨 밑이 479가 됩니다. 네 번째 인수는 화면 위쪽으로 일반적으로 양수값입니다. 우리는 화면 맨 위가 0 이 되기를 원하고 (익숙한 옛날 방식의 화면 구성) 따라서 네 번째 인수를 0으로 놓습니다. 이렇게 해서 y 축은 0부터 479 의 값 (480 픽셀) 이 됩니다.

마지막 두 인수들은 z 축의 값입니다. Z 축은 여기서는 상관하지 않으므로 범위를 -1.0f 에서 1.0f 로 놓아서, z 축의 0.0f 에 그려진 것을 보기에 적당하게 합니다.

정사영 뷰를 설정한 다음 모델뷰 매트릭스를 선택하고 초기화합니다.


GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
if (height==0)
{
height=1;
}

glViewport(0,0,width,height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}


초기화 코드에 몇 개의 새 명령들이 있습니다. 먼저 텍스쳐를 읽는 것으로 시작합니다. 만일 텍스쳐가 올바르게 읽히지 않으면 프로그램은 오류 메세지를 출력하고 종료합니다. 텍스쳐를 만들고 나서 글꼴 셋을 만듭니다. 여기서는 오류 메세지를 만들지 않았지만, 원하시면 만드셔도 됩니다.

글꼴이 만들어지면 초기화를 시작합니다. Smooth shading 을 켜고, 화면 색을 검은 색으로 하고 depth clearing 을 1.0 으로 합니다. 그 다음은 새로운 코드입니다.

glHint() 는 OpenGL 의 그리기 방법을 정합니다. 여기서는 OpenGL 에게 line smoothing 을 할 수 있는 최고 품질로 그리도록 합니다. 이 명령으로 안티 알리아싱이 활성화됩니다.

마지막으로 블렌딩을 활성화하고 안티 알리아싱 그리기가 가능한 블렌딩 모드를 선택합니다. 블렌딩은 선분과 배경 이미지가 잘 섞이게 하는 데 필요합니다. 블렌딩이 없으면 화면이 얼마나 엉망인지 보고 싶으시면 한 번 꺼보십시오.

한 가지 중요한 점은 안티 알리아싱이 잘 동작하지 않는 것처럼 보인다는 사실입니다. 이 게임의 물체들이 작기 때문에 안티 알리아싱이 제대로 동작되는지 발견하기 어렵습니다. 안티 알리아싱이 켜졌을 때 적들의 찌그러진 선들이 부드럽게 되는지 잘 보십시오. 물론 주인공과 모래시계의 출력도 향상됩니다.


int InitGL(GLvoid)
{
if (!LoadGLTextures())
{
return FALSE;
}

BuildFont();

glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
return TRUE;
}


이제 그리기 코드입니다. 이곳이 바로 마술이 현실로 드러나는 곳입니다.

화면을 검은 색으로 지우고 depth buffer 를 지웁니다. 다음에 글꼴 텍스쳐 (texture[0])를 선택합니다. 보라색으로 “GRID CRAZY”라는 글자를 화면에 그릴 것이므로 색상을 빨간색과 파란색을 최대 밝기로 놓고 녹색은 반으로 맞춥니다. 색상을 선택한 다음 glPrint() 함수를 호출합니다. GRID CRAZY 를 x 축으로 207 (화면 중앙), y 축으로 24(위아래)에 놓습니다. 글꼴 셋 0을 선택해서 큰 글꼴을 사용합니다.

화면에 글씨를 새긴 다음 색상을 노란색(빨간색 최대, 녹색 최대)으로 바꿉니다. 화면에 Level: 과 변수 level2를 그립니다. 변수 level2는 3보다 큰 숫자일 수 있습니다. 변수 level2는 화면에 보이는 레벨의 숫자를 갖고 있습니다. %2i는 화면에 출력되는 판 수가 2자리 수 이상을 원하지 않는다는 뜻입니다. 변수 I 는 정수를 뜻합니다.

레벨 수를 화면에 출력하고 나면 같은 색상으로 바로 밑에 판 수를 출력합니다.


int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glColor3f(1.0f,0.5f,1.0f);
glPrint(207,24,0,"GRID CRAZY");
glColor3f(1.0f,1.0f,0.0f);
glPrint(20,20,1,"Level:%2i",level2);
glPrint(20,40,1,"Stage:%2i",stage);


이제 게임 끝인지를 검사합니다. 만약 게임이 끝이라면 변수 gameover 는 TRUE가 됩니다. 만약 게임이 끝이라면 glColor3ub(r,g,b)함수를 이용해서 임의의 색상을 선택합니다. 3f대신에 3ub를 사용함으로써 0부터 255사이의 정수 값으로 색상을 선택할 수 있습니다. 게다가 0.0f부터 1.0f사이의 난수를 만드는 것보다 0부터 255사이의 난수를 만드는 것이 더 쉽습니다.

임의의 색상이 선택되었으면 게임 타이틀 오른쪽에 GAME OVER 라는 글씨를 새깁니다. GAME OVER 바로 밑에 PRESS SPACE 를 새겨서 주인공이 다 죽었고 스페이스바를 누르면 게임을 새로 시작할 수 있음을 알려줍니다.


if (gameover)
{
glColor3ub(rand()%255,rand()%255,rand()%255);
glPrint(472,20,1,"GAME OVER");
glPrint(456,40,1,"PRESS SPACE");
}


만약 주인공이 아직 남았으면 게임 타이틀 오른쪽에 움직이는 주인공 캐릭터의 움직이는 이미지를 그립니다. 이렇게 하기 위해서 루프를 0부터 현재 남아있는 주인공의 숫자 빼기 하나만큼 돌립니다. 하나를 뺀 이유는 현재 살아있는 주인공은 현재 조종하고 있기 때문입니다.

루프 안에서 먼저 뷰를 리셋하고 그 다음에는 오른쪽으로 490 픽셀 더하기 loop1 곱하기 40.0f 만큼 이동합니다. 이렇게 해서 움직이는 주인공 캐릭터는 서로 40픽셀씩 떨어져서 그려지게 됩니다. 첫 번째 움직이는 이미지는 490+(0*40)(=490) 위치에 그려지고, 두 번째 이미지는 490+(1*40)(=530) 위치에 그려집니다.

이미지를 그릴 위치로 이동한 다음에 player.spin 에 기록된 값에 따라서 시계방향으로 회전합니다. 이렇게 해서 현재 살아있는 주인공과 반대 방향으로 남은 주인공 이미지들이 회전하게 됩니다.

그 다음에 녹색을 선택하고 이미지를 그리기 시작합니다. 선을 그리는 것은 마치 사각형이나 다각형을 그리는 것과 유사합니다. 그리기 시작을 glBegin(GL_LINES)로 해서 OpenGL에게 이제부터 선분을 그릴 것을 알립니다. 선분은 두 개의 꼭지점을 갖습니다. glVertex2d함수를 이용해서 첫 번재 점을 잡습니다. glVertex2d는 z 값이 필요없습니다. 첫 번째 점은 현재 x 위치에서 5 픽셀 떨어진 곳, y 위치에서 5 픽셀 위에 위치하여 왼쪽 윗부분을 표시합니다. 첫 번재 선분의 두 번째 점은 x 위치에서 5픽셀 오른쪽, 그리고 5픽셀 아래이고, 오른쪽 아래 부분을 표시합니다. 두 번째 선분은 오른쪽 위에서 왼쪽 아래로 긋습니다. 이렇게 하면 화면에 녹색 X 표시가 그려집니다.

그 다음 반시계방향(z 축으로)으로 좀 더 회전하지만 이번에는 속도의 반만큼만 회전합니다. 그리고 어두운 녹색(0.75f)을 선택하여 다른 X 를 그리는데, 5 대신에 7을 사용합니다. 이렇게 하면 처음의 X 표시 위에 크고 어두운 X 가 표시됩니다. X 는 천천히 회전하기 때문에 마치 밝은 X 가 위에서 돌아가는 듯한 느낌을 주게 됩니다.


for (loop1=0; loop1 {
glLoadIdentity();
glTranslatef(490+(loop1*40.0f),40.0f,0.0f);
glRotatef(-player.spin,0.0f,0.0f,1.0f);
glColor3f(0.0f,1.0f,0.0f);
glBegin(GL_LINES);
glVertex2d(-5,-5);
glVertex2d( 5, 5);
glVertex2d( 5,-5);
glVertex2d(-5, 5);
glEnd();
glRotatef(-player.spin*0.5f,0.0f,0.0f,1.0f);
glColor3f(0.0f,0.75f,0.0f);
glBegin(GL_LINES);
glVertex2d(-7, 0);
glVertex2d( 7, 0);
glVertex2d( 0,-7);
glVertex2d( 0, 7);
glEnd();
}


이제 격자를 그릴 차례입니다. 변수 filled 를 TRUE 로 설정해서 격자가 완전히 채워졌음을 프로그램에 알립니다. (왜 이렇게 하는지는 조금있으면 아시게 됩니다)

바로 다음에 선분의 굵기를 2.0f 로 해서 격자를 더 선명하게 보이도록 두꺼운 선분으로 그립니다.

그 다음 안티 알리아싱을 끕니다. 왜냐하면 이것이 좋은 기능이긴 하지만 CPU 에 부하가 많이 걸립니다. 여러분의 그래픽 카드가 끝내주는 것이 아닌 이상 안티 알리아싱을 켜게 되면 속도가 많이 줄어들게 됩니다. 해보고 싶으시면 해보셔도 됩니다.

뷰는 재설정되었고, 이제 루프 두 개를 돌립니다. 변수 loop1 은 왼쪽에서 오른쪽으로, loop2 는 위에서 아래쪽으로 훑습니다.

선분의 색상을 파란 색으로 설정하고 그리고자 하는 수평 선분이 이미 지나친 곳인지를 검사해서 만일 그렇다면 색상을 흰 색으로 선택합니다. hline[loop1][loop2] 의 값이 TRUE 이면 그 선은 이미 지나간 곳이고, FALSE 이면 아직 지나치지 않은 곳입니다.

색상이 파란 색이나 흰색 중에서 선택되었으면, 선분을 그립니다. 먼저 해야 할 것은 오른쪽으로 너무 많이 가지 않았는가 확인하는 일입니다. 우리는 loop1 이 9보다 클 때 선분을 긋거나 선분이 채워져 있는지를 검사하면 안됩니다.

변수 loop1 이 유효한 값을 갖고 있는지 확인하였으면 수평 선분이 채워져 있는지를 확인합니다. 그렇지 않다면 filled 를 FALSE 로 놓아서 우리 프로그램에게 적어도 한 선분 이상은 채워지지 않은 것이 있음을 알립니다.

그 다음 선분을 그립니다. 첫 번째 수평 선분 (왼쪽에서 오른쪽) 은 20+(0*60)(=20) 에서 시작합니다. 이렇게 계속해서 80+(0*60)(=80) 까지 그려집니다. 선분은 오른쪽으로 그려집니다. 맨 마지막 선은 오른쪽 끝에서 시작해서 화면 바깥으로 80픽셀이 넘어가게 되기 때문에 우리는 11 번 선을 그릴 필요가 없습니다.


filled=TRUE;
glLineWidth(2.0f);
glDisable(GL_LINE_SMOOTH);
glLoadIdentity();
for (loop1=0; loop1<11; loop1++)
{
for (loop2=0; loop2<11; loop2++)
{
glColor3f(0.0f,0.5f,1.0f);
if (hline[loop1][loop2])
{
glColor3f(1.0f,1.0f,1.0f);
}
if (loop1<10)
{
if (!hline[loop1][loop2])
{
filled=FALSE;
}
glBegin(GL_LINES);
glVertex2d(20+(loop1*60),70+(loop2*40));
glVertex2d(80+(loop1*60),70+(loop2*40));
glEnd();
}


다음 코드는 비슷합니다. 그런데, 여기서는 오른쪽 대신에 너무 밑으로 내려가지 않았는지를 검사합니다. 이 코드는 수직선을 그리는 역할입니다.


glColor3f(0.0f,0.5f,1.0f);
if (vline[loop1][loop2])
{
glColor3f(1.0f,1.0f,1.0f);
}
if (loop2<10)
{
if (!vline[loop1][loop2])
{
filled=FALSE;
}
glBegin(GL_LINES);
&n
0 0
로그인 후 추천 또는 비추천하실 수 있습니다.
포인트 228,692
가입일 :
2003-02-18 14:12:30
서명 :
미입력
자기소개 :
미입력

최신글이 없습니다.

최신글이 없습니다.

댓글목록 0

등록된 댓글이 없습니다.
전체 529 건 - 10 페이지
2005.03
07

[App 개발] oracle 10g를 페더에 설치가 가능한가요??

이번 학기에 데이터 베이스 수업과.. JAVA수업을 듣게 되었는데.. JAVA는 아이북에서 설치가 가능하다고 하신거 같은데.. oracle 10g는 맥 서버용으로 나온건 알고 있습니다.. 그런데 그걸 그냥 일반 페더에도 깔수가 있…

2005.02
18

[App 개발] 한글 파일이름 open 이 원래 안되나요?

python 에서 한글 파일 이름으로 write 하려고 open 했는데 에러가 나는군요. 다른 프로그램으로 open 해도 화일이름이 한글이면 에러가 나는 것 같습니다. 한글이름이면 open 시스템콜이 안되나 봅니다 예) >>> f = ope…

2005.02
12

[App 개발] gnu c library

mac os x 에 설치된 c library 는 gnu c library 가 아니군요. BSD 계열이니 당연한 것이겠지만서도..... 수치계산할 때 complex 형 변수를 선언할 수 없어 불편하군요. 그런데 c library를 손…

2005.02
10

[App 개발] hdf5설치 성공하신 분 있나요?

라이브러리 설치 문제가 계속 걸려서 fink 를 이용해 봤습니다만, 안되는군요. :-( libpng, libjpeg 등을 모두 설치해도 h5utils 를 configure 하는 도중에 이 라이브러리들이 없다고 하는군요. hdf5 역…

2005.02
01

[App 개발] hdf5 라이브러리는 어디에...

리눅스에서 제가 작성했던 코드를 가져와서 컴파일 하려 하니 hdf5 라이브러리가 없다며 실패하는군요. hdf5 를 포트에서 설치하면 될 줄 알았는데 그게 아니었나 봅니다. h5cc 등의 툴만 있지 실제적으로 C 코드에서 호출해서 …

2005.01
28

[App 개발] [질문] 개발자에게 있어서 맥이란 플랫폼이란...?

안녕하세요. 컴퓨터 전공하는 학생입니다. 4년전에 대학교 입학할 때 컴퓨터를 장만하면서 맥도 고려했었습니다. 큐브가 어찌나 이뻐 보이던지 ^^; 하지만 PC에 비해 너무 고가의 장비였고... 무엇보다 맥으로 코딩 작업이 …

2005.01
06

[App 개발] apple developer 사이트에서 샘플 긁어오기 스크립트

본격적으로 osx 공부를 해볼까해서 apple developer 사이트를 보면서 샘플을 하나하나 다운로드하니 노가다성이 심하다 생각되서 파이손 스크립트 하나 만들었습니다. :) 페이지에 있는 *.sit 파일들만 쭉 다 다운로드 해줍니다. 저는 터…

2005.01
02

[App 개발] 프로그래밍 공부하는 방법

-------------------------------------------------------------------------------- 그냥 나름대로 정리해봄.. ----------------------------------------…

2004.12
28

[App 개발] MPC 7448 그리고 MPC 8641

프리스케일 웹사이트에 드디어 MPC 7448 과 MPC 8641 이 정식으로 명명되어 대략 설명이 올라왔습니다. 정말 내년 초 파워북 G4 의 업그레이드가 헛소문만은 아닌가봅니다. MPC7448 은 200MHz 의 MPX 버스를 가지게 되었습니다…

2004.12
18

[App 개발] GUI 인터페이스의 vim

새로 iMac 을 장만하고, 프로그래밍을 해 보겠다는 꿈을 품고 Xcode 를 무작정 실행해 보니 확실히 잘 모를것들이 많더군요. 앞으로 어찌 공부해야 할지, 갈길이 멀군요. 일단 고지식하게 Vim 을 찾았습니다. 터미널에 vi 는 있었지만, …

2004.12
06

[App 개발] 유용한 MacOS X external commands

요즘 타 맥관련 사이트에서도 열심히 글타래를 정독하면서 OS X의 근본적인 unix나 이래저래 공부를 하고 있습니다. 그중에서 unix 커맨드중에서 유용한 것들에 대한 설명이 되어있는 글을 보고 이렇게 올려드려요~ 공부하시는 분들에겐 도…

2004.11
29

[App 개발] MOD Player 를 만들어보자 2

지난 4월이었던가요 유닉스용 소스에 퀵타임 루틴을 첨가하여 간단하게 MOD 플레이어를 만들어본 적이 있는 것을 기억하실 것입니다. 그 때에는 첫 번째 시도이기도 하고, 괜찮은 소스를 입수하는 것도 여의치 않아서, 오리지날 4채널 MOD 포맷만을 지원했…

2004.11
17

[App 개발] MACOSX용 BBS WebStation 1.0 공개합니다.

MACOS용 BBS WebStation 1.0 공개합니다. 패키지로 구성된 파일을 실행하시면 자신의 MACOSX에서 BBS를 운영하실 수 있습니다. Perl 기반으로 작성되어있으며 FileDB를 사용하므로 별다른 작업없이 커뮤니티 구성이 가능합…

2004.11
11

[App 개발] 슈퍼컴퓨터 컨퍼런스 2004

제가 살고있는 피츠버그에서 슈퍼컴퓨터 컨퍼런스가 열리고 있습니다. 저는 오늘 하루 전시회 입장권만 구입해서 잠시 구경을 했습니다. 원래는 차기에 구매할 number crunching 기계 중에서 물망에 오르고 있는 4-way Opteron 제품을 직접…

2004.11
07

[App 개발] eclipse 사용해보시지 않으실래요..

안녕하세요.. 일본머그지기 시니입니다.. 저도.. 오픈소스를 넘 좋아해서리.. ㅋㅋㅋ 그나저나.. 개발하시는분들중엔 사용하고 계실지 모르지만.. 전 자바를 좋아해서리..ㅋㅋㅋ 새로나온.. 머 좀 지났지만 이클립스 3.0.1 함 사용해보세요.…

2004.11
03

[App 개발] 신형 아이북, 파워맥 벤치마크 결과

아이북, 파워맥 1.8GHz 벤치마크 느린 버스속도가 싱글 파워맥 성능저하의 요인 By James Galbraith 최근 애플에서 신형 아이북과 저가형 파워맥 G5가 발표되었습니다. 전체 리뷰를 진행하면서 동시에 Speedmark 테스트 …

2004.10
31

[App 개발] 게임엔진 NeoEngine 의 컴파일

SourceForge.net 에서 제일 인기있는 공개 소스 버젼 게임엔진 NeoEngine 이 있습니다. 모질라 라이센스를 따르고 있어서 소스의 변경 수정이 자유롭다는 특징이 있고, 공개 버젼 중에서는 가장 완성도가 높은 라이브러리가 아닌가 생각됩니다…

2004.10
18

[App 개발] [ 급질문 ] 맥용 웹하드 정도 만들어 볼려면..

음... 맥용 웹하드 정도 만들어 볼려면 어느정도 지식이 필요 할까요 아직 맥을 구경도 못해봤습니다..-_-;;; 맥이 어떻게 켜지는지도 모르고.... 맥에 관심이 어느날 부터 가기 시작하던데... 그런데 너무 맥에 관한 자료가 없더군요.. fi…

2004.10
13

[App 개발] X Code에서 include 포함 파일이나 라이브러리 파일의 경로는 어떻게 지정하나요 ?

안녕하세요.. 비주얼 스튜디오 같은 곳에서는 포함 파일이나 라이브러리 파일을 옵션에서 설정해 줄 수 있었습니다. X Code 에서는 이를 어떻게 설정해 주어야 하나요 예를 들어 /Volumes/Data/SDKLib 라는 곳에…

2004.09
10

[App 개발] 아이맥 G5 의 특이한 점 - 개발자 문서에서 살펴본 결과

아이맥 G5 의 개발자 문서가 드뎌 공개되었군요. 메모리 버스가 어떻게 구성되어 있는지 상세히 밝혀져 있습니다. 구형 파워맥 G5 의 구성과 비교해 보겠습니다. 신형 파워맥 G5 에서는 변경된 사항이 있을지도 모르겠습니다. 1. …

2004.08
31

[App 개발] 아이맥 G5 의 특이한 점???

개발실에 쓸 글은 아닙니다만... 딱히 좋은 장소가 없어서 여기에 글을 올립니다. 일단 오늘(8월 31일) 발표된 새 아이맥은 날씬하고 보기 좋고, 게다가 가격도 무척 저렴해서 크게 인기를 끌 수 있는 가능성이 풍부한 제품이라고 생각합니다. …

2004.07
05

[App 개발] 질문하나 있습니다.

아.. 소스를 카피해온다는 것이 못해왔네요. 다름이 아니라, Xcode에서 Interface Builder로 Custom View를 하나 만들었고, 이 클래스로 파일을 생성(.h, .m파일)하여 Xcode에서 .m파일에 이 Custom View에…

2004.05
24

[App 개발] 여기 아무두 안오세용? 도와주세요.

이제 막 코코아 개발을 시작하려고 하는 초보입니다. C에 대해선 어렴풋이나마 알고 있고 잘 알지 못하는 중에 코코아로 바로 뛰어들었는데요. 많이 부족함을 느낍니다. 천천히 하고있는데... 열심히 하고 싶지만 시간이 없네요. 지금 OR…

2004.05
15

[App 개발] 맥에서 Qt 사용 어떤가요?

사운드신세시스 프로그래밍을 공부하는데요 아무래도 GUI 가 필요해서 GUI 프로그래밍을 보려하는데, 리눅스환경에서 만들고 있어서 Qt 를 사용해서 GUI 를 만들어보려고요. 그런데 Qt 소개를 자세히 보니까 멀티플랫폼 API 이어…

2004.04
21

[App 개발] NeHe Lesson 23

무척 오랫만입니다... ㅎㅎㅎ 먹고 사는 것이 바쁘다보니... 일단 샘플 코드의 구현은 흥미로운 것 위주로 하도록 하고, 나머지는 텍스트를 익히는 것에 중점을 두려고 합니다. (제가 게을러졌다는 것을 우회적으로 표현하는 것입니다. ㅡㅡ;;;) …

2004.04
02

[App 개발] 국제컴퓨터, 소프트웨어, 통신전시회에 참석 하고자 분들 (리플부탁)

- 컴퓨터:휴대형단말기, PC(Desktop, Notebook, Laptop,Palmtop, Etc), 매킨토시, 네트웍컴퓨터, 서버, 워크스테이션, 메인프레임, 프리젠테이션장비, 기타 - 소프트웨어:WINDOWS/NT/UNIX기반 시스템ɨ…

2004.03
11

[App 개발] ModPlayer 를 만들어보자

MOD 는 Amiga 의 음악 파일 포맷입니다. 사실 아미가에서 쓰였기 때문에 유명해졌다기보다는 많은 도스 게임들이 MOD 배경음악을 지원하면서 탄탄한 지원군을 많이 얻음으로 인하여 공개 소스들이 많이 돌아다니게 되고, 유저의 손에서 더욱 더 확장되고…

2004.03
10

[App 개발] 맥마메 분석 - 5 사운드 출력

맥마메 분석 – 5 사운드 출력 개인적으로 가장 관심있는 부분으로 접어들었습니다. 오랫동안 피씨 프로그래밍만 해오다 보니 매킨토시의 사운드 출력이 어떻게 이루어지는지를 궁금해 해 왔습니다. 최근에는 맥과 피씨가 유사한 칩셋들을 많이 공…

2004.03
09

[App 개발] 맥마메 분석 - 4 HID 루틴

맥마메 분석 – 4 조이스틱 입력 네 번째 시간이 되었습니다. 솔직히 저는 조이스틱 지원에 대해서는 별로 관심은 없습니다. (집에 조이스틱이 없거든요. 하하…) 애플 II 에서는 조이스틱이 없으면 완전 바보였지만, 이제는 입력장치로 마…

2004.03
06

[App 개발] 맥마메 분석 - 3 마우스 입력

맥마메 분석 &#8211; 3 마우스 입력 마우스 입력도 키보드 입력과 거의 비슷한 방식으로 구현되어 있습니다. 메인 윈도우 이벤트 핸들러로 마우스 입력 핸들러를 등록하는 것, 그리고 이벤트 핸들러에서 입력된 값을 마우스 상태 배열에 …

2004.03
05

[App 개발] 맥마메 분석 - 2 키보드 입력

맥마메 분석 사실 마메의 진짜 핵심은 프로세서 에뮬레이션, 비디오 프로세서, 사운드 프로세서 에뮬레이션 루틴이죠. 한 번 마메 소스를 열어보신 분들이라면 실로 방대한 에뮬레이션 루틴들을 보면서 놀라셨을 것입니다. 그런데, 에뮬레이터를 제…

2004.03
04

[App 개발] 수박 겉핥기 MacMAME 분석 - 1. 디스플레이

수박 겉핥기 MacMAME 분석 Multiple Arcade Machine Emulator 의 약자인 MAME 는 게임 센터의 PCB 게임들의 에뮬레이터로서 고전 게임 매니아들에게 사랑받는 프로그램입니다. 대부분 기종에 이식되어 있고, 매킨토시에…

2004.02
18

[App 개발] NeHe Lesson 22

22번은 작문도 상당히 엉터리고, 그래서 번역도 엉터리고, 소스도 엉터리고... 이것을 붙잡고 계속 늘어지고 있는 것보다는 어서 앞으로 나아가야겠다는 생각에 예제도 만들지 못하고 건너뛰게 되었습니다. 대단히 송구스럽습니다. 별로 도움 안 되는 22번이…

2004.02
10

[App 개발] 10 bytes extended 형 데이터 처리.

안녕하세요 계속해서 Aiff 파일을 공부하고 있는데요. 헤더에 들어가있는 short, long, char 등의 데이터형의 데이터는 쉽게 읽고 쓸수가 있는데, Wave 화일과는 달리 Aiff 파일은 Sample Rate 를 기록하는 데이…

2004.02
08

열람중 [App 개발] NeHe Lesson 21

늦었습니다. ^^ 이번에는 내용도 많고, 간단하긴 하지만 그래도 게임 제작이고, 원래가 윈도우용으로 제작된 소스를 이식해야 하는 것이라 빼먹은 부분도 많고, 그래도 대충 돌아가게끔 맞춰놓긴 했습니다만... 어쨌든 즐겨 주십시오. ^^ ------…

2004.02
03

[App 개발] NeHe Lesson 20

강의 20번째입니다. 비트맵 이미지 포맷은 거의 모든 컴퓨터, 모든 운영체제에서 지원합니다. 사용하기 쉽고 텍스쳐로 읽고 만들기에 간단합니다. 지금까지 우리는 텍스트나 이미지를 출력할 때 배경을 지우지 않고 물체와 섞이도록 했습니다. 효과적이긴 하지만…

2004.02
01

[App 개발] Cocoa Design Patterns (7) 마지막

Facades 클래스 클러스터와 프록시를 설명할 때 이미 소개했습니다만, Facade(겉면 - 여기서는 포장지(Wrapper Facade)로 번역하겠습니다)는 복잡한 객체 집단을 간단히 단일화하여 보여주는 객체입니다. 포장지 패턴은 코코아에서 다른 …

2004.02
01

[App 개발] c++ file io 에서 기초적인 질문입니다.

Aiff 화일 헤더분석하는 프로그램을 만들어보려고 하는데요, 그냥 콘솔형으로 하려고, gcc 를 사용해서 하고 있습니다. 파일 입출력을 위해 ifstream 을 사용하는데요, aiff 화일로 부터 1바이트 char 형 데이터를 읽기위해…

2004.01
31

[App 개발] NeHe Lesson 19

강의 19번째입니다. 지금까지 여러 가지를 배워 오셨는데, 이제부터는 갖고 놀고 싶으실 겁니다. 저는 이번 강의에서 새로운 명령을 하나 소개하려고 합니다. 삼각 막대입니다. 아주 간단하고, 많은 수의 삼각형을 그리는 프로그램을 빠르게 만드는데 도움이 …

2004.01
30

[App 개발] Cocoa Design Patterns (6)

Notifications 코코아는 통지(notifications)기능을 이용해서 응용프로그램 내의 객체간에 중요한 일들이 발생했음을 알립니다. 어떤 통지 메세지들은 수신자가 여러 개일수도 있습니다. 물론 여러 개의 객체가 한 메세지를 보내거나 공시할…

2004.01
29

[App 개발] java2 network (chat server/client)

-- TCP기반의 에코서버/클라이언트 //EchoClientTest.java&nbsp;&nbsp; import java.io.*; import java.net.*; public class&nbsp;&nbs…

2004.01
29

[App 개발] 진짜 간단한 AWT 계산기입니다..

import java.awt.*; import java.awt.event.*; public class Calcurator_ex extends Frame implements ActionListener{ // 인스턴스 변수 선언 Butt…

2004.01
29

[App 개발] AWT java text 에디터입니다.

import java.awt.*; import java.awt.event.*; import java.io.*; class EditorDemo extends Frame implements ActionListener{ TextAr…

2004.01
29

[App 개발] NeHe Lesson 18

Quadrics Quadrics는 for 루프와 삼각함수를 이용하여 복잡한 물체를 그리는 방법을 뜻합니다. 강의 7 에서 사용한 코드를 이용할 것입니다. 일곱 개의 변수를 추가하고 텍스쳐를 바꾸어서 변화를 주었습니다. bool sp;…

2004.01
28

[App 개발] NeHe Lesson 17

이번 강의는 NeHe와 Giuseppe D’Agata에 의해 만들어졌습니다. 폰트때문에 힘드신 것 다 압니다. 지금까지 제가 만든 강의에서는 단순히 글자를 출력하는 것뿐만 아니라 3D 글자, 텍스쳐 매핑된 글자를 출력할 수 있고, 변수를 처리할 …

2004.01
25

[App 개발] CoreGraphics의 풀스크린 화면 만들기

박진철님께서 올리셨던 질문 중에 코코아에서 퀵드로우의 CopyBits대신 사용할 수 있는 방법으로서 아시는 분들은 다 아실만한 CGDirectDisplay 를 이용한 방법을 한 번 시도해 보았습니다. 프로그램은 심히 완성도가 떨어지는 관계로 감히…

2004.01
23

[App 개발] Cocoa Design Patterns (5)

Commands GOF의 패턴에 익숙하신 분들은 아마 타겟/액션이 마치 커맨드 패턴의 구현이라고 생각될 것입니다. 그러나 커맨드 패턴같은 것이 타겟/액션과 같은 구현이 이용된다 하더라도 Objective-C에서는 그것이 필요가 없습니다. 커맨드 패턴…

2004.01
22

[App 개발] Cocoa Design Patterns (4)

Enumeration 코코아의 모든 콜랙션 클래스는 계수기를 제공합니다. 이 패턴은 GOF의 반복기 패턴과 비슷합니다. 계수기는 객체의 집합을 훑어내고 각 객체에 어떤 일을 수행하는 방법을 제공합니다. 특정한 집합에 대하여 특수한 루프를 짜 주는 대…

2004.01
22

[App 개발] NeHe Lesson 16

이번 강의는 Chris Aliotta가 제작하였습니다. 당신의 OpenGL 프로그램에 안개를 넣고 싶으십니까 이번 강의에서 바로 그 방법을 보여드리려고 합니다. 저는 강의를 쓰는 것은 처음이고, OpenGL/C++ 프로그래밍은 근래에 시작한 것이…