NDS Development Trial

From KBase

Jump to: navigation, search

Main Page >> NDS Homebrew Tutorial

Contents

[edit] Day 1

DevKitPro 에 들어 있는 Programmers Notepad 2 를 실행시킨다. 깔끔하니 잘 만든 IDE 인 것 같아 보인다.


Project 를 열어야 하니 하나 복사해 보자. DevKitPro 가 설치한 Shortcut 중 MSys 라는 것을 실행시킨다. cygwin 과 비슷하지만 mingw32 를 쓴 거란다. sample 을 복사한다.

 scgyong@GPC ~/ndsdev
 $ cp -R /c/Apps/devkitPro/examples/nds/templates/arm9 testprj


Programmers Notepad 2 로 만든 프로젝트를 열어본다. C:/Apps/devkitPro/msys/home/scgyong/ndsdev/testprj/template.pnproj 가 project 파일이다.


Menu - Tools - make 를 무작정 실행해 본다. 컴파일이 실패한다. arm-eabi-gcc 가 제대로 실행이 안 되는 듯하다. 이번엔 msys 에서 command line 으로 실행해 봤는데 이번엔 command not found 가 나온다. 에러 메시지는 다음과 같다

This application has requested the runtime to terminate it in an unusual way. Please contact the application's support team for more information.


우째야 하는 걸까. 고민을 좀 하다가 에러 메시지로 검색을 해 보니 http://support.microsoft.com/kb/884538 이런 글이 나온다. VC2003 이 문제인가. MSVCRT.DLL 이나 MSVCIRT.DLL 을 어디선가 다운로드하여 교체해 보았지만 소용이 없다. 뭐가 문제일까 고민했지만, 결국 Windows XP 를 다시 설치하는 것으로 해결했다 -_-


결국, DevKitPro 를 설치한 것 외에 한 일이 없다 :(

[edit] Day 2

  • template/arm9 를 testprj 로 복사하여 빌드하는 것이 성공했으니 Emulator 로 먼저 돌려 보기로 한다.

http://www.dev-scene.com/NDS/Tutorials 에서는 Emulator Section 에서 다음과 같은 얘기를 한다.

Dualis http://dualis.1emulation.com/
NO$GBA http://nocash.emubase.de/gba.htm
Dualis is free and slightly more advanced than NO$GBA. But the $15 homebrew version of NO$GBA has some very impressive and incredibly useful debugging features. I recommend you grab Dualis and if you get serious about homebrew you can grab NO$GBA another time.

얼마나 serious 해질지는 모르지만 NO$GBA 를 받아 보기로 한다. 받아서 실행하니 바로 ROM 파일을 묻는다. 방금 컴파일 한 testprj.nds 를 선택해 주니 touch 의 x,y 를 잘 찍어 준다. 예상한 대로, Emulator 에서는 mouse button 을 누르는 것이 touch 이다. 그런데, 아직 키는 뭔지 모르겠다.


내친김에 어둠의 세계에서 다운로드받은 롬도 돌려본다. 실행은 되는데, 세이브 파일이 없다는 에러 메시지가 나온다. 일단은 관심사가 아니니 패스. Tutorial 에 있는 내용으로 바꿔서 돌려 보니 역시 잘 나오는 것 같다.


뭘 만들어 볼까. 고민 하다가 그냥 간단히 Block 격파 프로그램을 짜 보기로 한다. 간단히 사각형을 그리도록 하고 좌표를 조금씩 변경시켜 가면서 그려 본다. VBlank 를 기다려 배경을 그리고 조그만 블럭 하나를 그리는 데 생각보다 느리다. 배경을 안 그려봤는데 그래도 느리다. VBlank 를 기다리지 않고 그려 보니 엄청 빠르다.


어떤 접근 방법이 좋을지 아직 감이 안 온다.


[edit] Day 3

간단히 클래스들을 만들어 보았다. Ball, Graphics, Math, Scene 이다. Scene 은 현재 active 한 화면을 나타내 보려고 했고 나중에는 Scene 에서 파생하여 여러 Scene class 들을 만들어 보려고 한다. Ball 은 말 그대로 움직이는 놈. Graphics 는 화면을 추상화한 singleton object 이다. Graphics 에는 GraphicsImpl 이라는 class 를 따로 두어 Pimpl 방식을 사용했다. 좌표는 고정소수점을 사용하고 cos, sin 등의 함수를 Math 의 static method 로 두었다. 삼각함수는 미리 고정소수점으로 계산해 둔 값을 배열에 넣어 두고 사용했다. swiWaitForVBlank() 를 안 부르면 엄청 빠르다...


[edit] Day 4

devkitPro 에 들어 있는 여러 예제들을 살펴 본다. 2D Demo 로 16bit color bmp, Complex_2D 등을 보았는데 그닥 쓸만한 것 같지가 않다. devkitPro 홈페이지로부터 libnds 에 대한 documentation 을 찾아 보니 http://www.drunkencoders.com/documents/DS/ndslib.htm 이게 나온다. 대충 reference 로 사용할 수 있어 보인다.


이제는 Alpha blending 이 포함된 Image Blitting 을 해 보려고 한다. 회사에 빠른 알고리즘이 있지만 회사꺼니 여기에 쓰긴 뭐하고.. google 에서 fast alpha blending 으로 검색해서 http://maemo.org/pipermail/maemo-developers/2007-January/007685.html 를 찾았다. 뭔가 이용해 볼 만 한 것이 아닐까.


그런데, 짜증나게도 엉뚱한 곳에서 시간을 많이 쓰고 말았다. cygwin 에 gd 를 설치하고 링크를 하려는데 에러가 나는 것이다.

$ g++ -lgd main.cpp
C:\Temp/ccNHnQPe.o:main.cpp:(.text+0x32): undefined reference to `_gdImageCreateFromPng'
C:\Temp/ccNHnQPe.o:main.cpp:(.text+0x5a): undefined reference to `_gdImageDestroy'
collect2: ld returned 1 exit status

아무 성과 없이 두어 시간이 흘러 버렸다. 젠장. 여기서 또 한 일 없이 멈춰야 하나.

다시 이리 저리 해 보다가 방법을 찾았다. 우습게도 그 해결 방법은 linker option 을 뒤에 쓰는 것이다.

$ g++ main.cpp -lgd

다음은 http://www.delorie.com/djgpp/doc/ug/compiling/gcc.html 의 일부이다. 위 방법을 알아낸 후 열심히 검색해서 겨우 찾았다.

The -l options are used to add libraries to your program. Note that order is important! You should always list libraries after all your objects. If you don't, gcc might not realize that it needs them until it's too late. The -l option is a shortcut for linking a library, because you can always just list the library on the command line (like "gcc hello.o mylib.a"). The benefit of the -l option is that you don't need to know where the library is. This is used for the standard libraries, and in fact, gcc will automatically add -lc to whatever you type in order to get the standard C library (libc.a). Note that with the -l option, you only need to specify part of the library name. gcc assumes that the library name starts with "lib" and ends in ".a", so -lfoo would refer to libfoo.a and would be found wherever the standard libraries are kept.

gd 를 이용하여 png 를 읽고 새로운 포맷인 gpn 을 정의했다. data 는 위에서 찾은 알고리즘에서 제안한 포맷이다.

struct Image {
 int signature;
 short width;
 short height;
 int size;
 unsigned int data[1];
};

정의한 대로 box.gpn 을 만들어 data/ 에 넣으면 box_gpn.o 와 box_gpn.h 가 생성된다. 이걸 읽어서 화면에 표시해 보니, 여전히 뭔가 비트 배열이 이상한 듯 하다. Alpha blending 에 아직 문제가 있는 듯하다. 시간이 너무 오래 걸려서, 나중에 계속 해야겠다.


[edit] Day 5

Google신으로부터 따라가다가 http://www.virtualdub.org/blog/pivot/entry.php?id=117 라는 것을 찾았다. 이걸 읽으니 지난번 빠른 alpha blending 의 원리가 이해가 된다. 이상하게 나오는 이유를 찾아 봐야겠다.


[edit] Day 6

드디어 이상하게 나오는 원인을 알아냈다. 바로 pixel format 이 그 원인이었던 것이다! 위 문서들은 RGB565 를 기반으로 설명된 문서들이었지만, NDS 는 RGB555 를 사용하는 게 문제였던 거다. 깨끗하게 나오는 화면을 보면서 쾌감을 느낀다.

다음은 gd 를 사용한, gpn 파일 생성 코드이다.

    Image *gpn = (Image *)buf;
    gpn->signature = *(int *)"gpng";
    gpn->width = gdImageSX(img);
    gpn->height = gdImageSY(img);
    gpn->size = size;

    unsigned int *p = gpn->data;
    for (int y = 0; y < gpn->height; y++) {
        for (int x = 0; x < gpn->width; x++) {
            int color = gdImageGetPixel(img, x, y);
            int r = gdTrueColorGetRed(color);
            int g = gdTrueColorGetGreen(color);
            int b = gdTrueColorGetBlue(color);
            int a = 255 - (gdTrueColorGetAlpha(color) << 1);

            unsigned int n = (a+1) / 8, xx = (b>>3<<10)|(g>>3<<5)|(r>>3);
            xx = (xx | (xx << 16)) & 0x3E07C1F;
            unsigned int pcolor = xx | (n << 15);

            char bits[33];
            unsigned pp = pcolor;
            for (int i = 0; i < 32; i++) {
                bits[i] = (pp & 0x80000000) ? '1' : '0';
                pp <<= 1;
            }
            bits[32] = 0;
            printf("%2d,%2d => %08X => %02X %02X %08X.%s\n", x, y, color, a, n, pcolor, bits);
            *p++ = pcolor;
        }
    }

원래 코드에서 달라진 점은

  1. xx 를 계산할 때 RGB555 에 맞게 shift 하는 것
  2. alpha 값 (0~32) 을 15 bit shift 하는 것

이걸 화면에 표시하는 코드는 다음과 같다

    int w = img->getWidth();
    int h = img->getHeight();

    nds_color *left = m_pimpl->framebuffer + y * SCREEN_WIDTH + x;
    nds_color *right = left + w;
    nds_color *bottom = left + h * SCREEN_WIDTH;

    u32 *src_left = (u32 *)img->getData();
    u32 *src_right = src_left + w;
    //u32 *src_bottom = src_left + h * w;

    while (left < bottom) {
        nds_color *curr = left;
        u32 *src_curr = src_left;

        for (; curr < right; curr++, src_curr++) {
            u32 src = *src_curr;
            u32 dst = *curr;
            u32 alpha = (src >> 15) & 0x3F;
            //src = ((src & 0x3E07C1F) * n / 32) & 0x3E07C1F;
            dst = (dst | (dst << 16)) & 0x3E07C1F;
            u32 result = ((src - dst) * alpha / 32 + dst) & 0x3E07C1F;
            *curr = result | (result >> 16);
        }

        left += SCREEN_WIDTH;
        right += SCREEN_WIDTH;

        src_left += w;
        src_right += w;
    }

깨끗하게 잘 나온다.

Personal tools
Wiki Help (mediawiki.org)