대변 파이터 (WIZ 이식作)

12년 전에 Pascal로 만들었던 것을 원본 소스를 바탕으로 WIZ로 포팅을 한 것이다.

- Pascal + x86 Assembler 소스를 C++로 컨버팅
- DOS용 디바이스 제어 부분을 WIZ로 포팅
- 640*400 -> 320*240 출력을 위한 가상 해상도 제어

등에 시간을 할애 했으며, 아래 글에 있는 'Wiz용 game 제작 샘플'에 공개한 플랫폼을 이용해서 만든 것이다. 소스의 경우에는 이전의 pascal code를 그대로 번역했기 때문에 전혀 정리가 되지 않았다는 이유로 올리지는 않는다.

사용자 삽입 이미지

my_23rd_shitfigh_0.98.zip

GP2X Wiz용 대변 파이터


MS Windows용 대변 파이터 (아직 바이너리 없음)

Posted by 안영기

2009/08/16 09:31 2009/08/16 09:31
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/16

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

Wiz용 game 제작 샘플

MS WindowsGP2X wiz에서 동시에 개발하는 방법 중 한 가지를 소개한다.

이 글은 OpenGL을 다룰 줄 알고 linux 빌드에 불편함을 없는 사람을 기준으로 작성되었다.

다운 받기 (643KB)

 

1. 디렉토리 설명

.

+---bin                  최종 결과물이 남는 디렉토리

+---external             외부 헤더와 라이브러리 모음

|   `---wiz              OpenGL ES 1.1용 라이브러리

|       `---GLES         OpenGL ES 1.1용 헤더 디렉토리

`---src                  게임 소스 디렉토리

    +---app              게임 디렉토리

    `---avej_lite        게임 플랫폼

        `---adaptation   게임 플랫폼의 포팅 영역

 

2. Win32용 빌드와 실행 방법

 

./manoeri_25th.dsw VC++ 6.0 work space 파일인데, VC++ 6.0, VC++ 2005, VC++ 2008에서 모두 읽을 수 있기 때문에 dsw로 배포를 하는 것이다. 이 파일을 읽은 후 별 다른 설정 없이 빌드를 하면 bin 디렉토리에 실행파일이 생긴다. 실행 후 화살표 키를 사용하여 움직이고 ESC 키로 종료하면 된다. Win32의 경우는 그래픽 카드의 특성을 타는 부분이 있기 때문에 모든 PC에서 정상 동작 한다고는 보장할 수 없다.

 

Win32용으로 실행에 필요한 파일은 다음과 같은데, 같은 디렉토리에 넣고 실행하면 된다.

 

bin/manoeri_25th.exe

bin/libgles_cm.dll

bin/deja_dun.tga


WIN32에서 MingW를 사용하는 사람들을 위한 Makefile.mingw32가 추가되었다. mingw32.exe에 대한 path가 지정되어 있다면 그냥 빌드 가능하고, 그렇지 않다면 컴파일러 path 부분만 수정하면 정상적으로 빌드하고 실행 가능 할 것이다. (Cygwin + MingW에서 테스트 하였음)

 

3. WIZ용 빌드와 실행 방법

 

./Makefile GNU make file이다. 자신이 사용하는 WIZ용 컴파일러의 이름이 arm-linux-g++ 이면서 path가 지정되어 있다면 아무런 설정 없이 ‘make’를 하면 bin 디렉토리에 실행 파일이 생긴다. 만약 위의 조건을 만족하지 못한다면 Makefile 3번 째 줄에 있는 ‘CROSS_COMPILE  = arm-linux-’ 를 자신의 환경에 맞게 수정하면 된다.

 

WIZ용으로 실행에 필요한 파일은 다음과 같은데, 같은 디렉토리에 넣고 실행하면 되는데, 실행 후 화살표 키를 사용하여 움직이고 MENU 키로 종료하면 된다.

 

bin/manoeri_25th.gpe

bin/libopengles_lite.so

bin/deja_dun.tga 


4.
라이선스 설명

 

OpenGL ES와 관련된 헤더와 라이브러리의 출처는 다음과 같다.

 

- external/wiz/libgles_cm.lib, libgles_cm.dll
PowerVR OpenGL ES 1.1 Win32 데모에 있던 것이다.

- external/wiz/libgles_port.a
아직 비공개인 아카이브에서 ES 포팅부만 추출해서 만든 것이다.

- external/wiz/libopengles_lite.so
지폐인
자료실에 공개된 것이다.

- external/wiz/GLES 의 헤더
공개된 quake 소스에서 가져 온 것을 조금 수정한 것이다.

 

나머지는 직접 구현한 것이며(외부 추출 코드의 경우는 코드에 출처를 명기했음) 게임 개발 참고용으로 누구나 사용 가능하다.

 


5.
기타, 개발 시 유의 사항

 

MS Windows에서의 빌드는 아무런 문제가 없을 것이다. 단지 WIZ OpenGL ES 1.1 full spec.아 아니라 업체에서 정의한 OpenGL ES 1.1 lite라는 spec.이다 여기서 제한되는 기능에 대해서는 지폐인에 공개된 문서를 숙지하는 방법 밖에는 없다. 예를 들어 스펜실 버퍼를 사용하여 Win32에서 개발을 하여 결과를 보았더라도 그것이 WIZ에서 빌드를 하여 실행을 하면 제대로 실행되지 않는다.

 

개발시 가장 큰 문제는 WIZ용 빌드에 있다. 현재 WIZapplication을 빌드 할 수 있는 툴체인은 3개 이상이 있다.

 

가장 먼저는 OpenWIZ로 공개된 비공식 컴파일러가 있다. 이것은 http://dl.openhandhelds.org/에서 구할 수 있으며 linux 상에서만 구동된다. 따라서 PC linux를 깔든지, VmWare 등의 방법으로만 개발이 가능하다. 이것으로 WIZ에서 OpenGL ES를 사용한 개발은 충분히 가능하다. 하지만 현재 공개되어 있는 libopengl_lite.so와는 floating point 관련되어 충돌이 나고 있다. 따라서 ‘quake for WIZ’에 포함된 nanoX와 같은 방법인 ‘shared object의 동적 로딩으로만 해결할 수 있을 것 같다.

 

두 번째는 GP2X용으로 공개된 Windows용 크로스 컴파일러가 있다. 이것은 이미 GP2X 시절에 공식 SDK로 릴리즈 된 것이며 SDL을 사용하는 수준의 게임은 GP2XWIZ에서 동시에 돌 수 있는 게임을 만들 수 있다는 것을 확인했다. 여기서의 목적은 WIZ OpenGL ES를 기반으로 개발하는 것이므로 이 컴파일러는 배제하도록 하겠다. (이 역시 libopengl_lite.so과는 빌드 당시의 libc의 버전이 달라서 문제가 발생한다)

 

마지막으로는 GPH가 공식적으로 배포 할(이 글을 쓰는 시점에는 공식 SDK가 공개되지 않았음) SDK에 포함된 크로스 컴파일러이다. 현재는 gcc 4.0.2glibc 버전은 2.3.6이며(EABI로 교체할 것이란 루머도 있기 때문에 공개 시 버전은 달라질 수 있음) 이 툴체인만이 현재로서는 일반 linux에서 하는 개발 방법과 동일하게 OpenGL ES link 할 수 있다.

 

그리고 WIZ에 사용된 pollux OpenGL ES는 표준과 동작이 다른 부분이 조금 보이는데, 그것은 embedded 개발자라면 적절히 피해 가야 하는 장애물이라 생각하면 될 것 같다. 이 글의 목적은 MS Windows에서 쉽게 개발한 후, 최소한의 노력으로 WIZ에 올리자는 것에 있으므로 중간 중간 WIZ에서 결과물이 동일하게 나오는지는 꾸준히 확인해봐야 한다.


Posted by 안영기

2009/07/26 12:33 2009/07/26 12:33
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/15

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

memset() 함수를 위한 헤더 파일은?

memset() 함수를 쓰기 위해 include 해야 하는 헤더 파일 때문에 종종 실수를 한다. 나는 아주 예전부터 <memory.h>를 사용해 왔고 대부분의 컴파일러에서는 문제를 일으키지 않았다.

 

내일 code release를 해야 하는 라이브러리가 있어서 여러 컴파일러에서 최종 문법 테스트를 한 후, 내가 라이선스를 가지지 못한 나머지 컴파일러에 대해서는 다른 분께 빌드를 의뢰했다. 그리고 의뢰 받은 쪽에서는 저 <memory.h>라는 것 때문에 오류가 난다는 통보를 해 줬다. 그래서 나는 즉시 <string.h>로 바꾸라고 메시지를 줬고 나머지 모두 빌드에 성공했다. <memory.h>를 못 찾을 때는 <string.h> include하면 된다는 것은 이전부터 알고 있었기 때문에 그렇게 대응한 것이지만 그때까지만 해도 그건 컴파일러의 잘 못이라고만 생각하고 있었다.

 

자리에 돌아와서 man page wikipedia에서 관련된 표준에 대해 조사를 해 보았다. 그런데 전부 다 표준은 <string.h>라고 나와 있었다. 매뉴얼을 제대로 보지 않은 내 잘 못이긴 하지만 대응되는 헤더가 그다지 직관적이지는 못하다는 생각도 동시에 든다.

Posted by 안영기

2009/05/28 19:18 2009/05/28 19:18
Response
0 Trackbacks , 1 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/14

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

헤더의 include 순서

어떤 순서로 배열해도 잘 굴러가기만 할 헤더의 배열 순서이지만 나는 아래와 같은 방법을 사용하고 있다

1. 그 Application의 헤더
2. 사용
Library의 헤더
3. 표준 헤더 

만약 app라는 이름의 application avejlib이라는 이름의 Library를 사용하고, 거기에다가 표준 입출력을 사용하고 있을 때 다음과 같이 사용한다는 것이다

#include app_type.h
#include app_traits.h
#include app_util.h
#include avejlib_renderer.h
#include avejlib_audio.h
#include avejlib_device.h
#include <stdio.h>
#include <vector>
#include <algorithm> 

이렇게 하면 실제 디펜던시와는 반대로 배열이 되는데, 이렇게 했을 때 library(주로 자체로 만든 것)가 제대로 디펜던시가 설정되었는지를 컴파일 시에 알 수 있기 때문이다.

예를 들어 apputil.h <vector>에 디펜던시가 있는데 그것을 내부적으로 해결해 놓지 않으면 위의 경우는 에러가 난다. 그렇게 하는 이유는 ‘어떠한 헤더도 그 헤더를 사용하기 위한 전제 조건을 알 필요가 없어야 한다’라고 생각하기 때문이다. 내가 “apputil.h”를 A()라는 함수를 쓰기 위해 include 했는데, apputil.h”의 B()라는 함수 때문에 생긴 <vector>에 대한 디펜던시를 알아야 할 필요가 없기 떄문이다

참고로 구글의 coding guideline은 이와 반대이며 그들도 그들 나름대로의 이유 때문에 그렇게 했을 것이다.

Posted by 안영기

2009/04/26 07:53 2009/04/26 07:53
Response
0 Trackbacks , 2 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/13

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

wchar_t에 대해

C 언어의 기본 기능인 L””을 사용하는데 wchar_t는 필수적이다. 하지만 이것 역시 #include <wchar.h> 해야만사용할 수 있으며 그것도 좀 이상하다. L”ABC” 라는 데이터를 선언 할 수 있지만 그것을 받아 오는 타입은 #include를 해야만 알 수 있다는 것 역시 이상하다. (물론 unsigned short 또는 unsigned long으로 가능하긴 하지만 컴파일러 마다 다르다)

 

Posted by 안영기

2009/03/15 10:19 2009/03/15 10:19
Response
0 Trackbacks , 3 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/12

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

size_t와 ptrdiff_t 에 대해

알고는 있지만 내가 잘 쓰지 않는 표준 타입에 size_t ptrdiff_t가 있다. size_t는 표준 함수(memset() )들의 파라미터에도 쓰이고 있지만 실제로는 unsigned long 등으로 간주해버리기 일쑤였다. VC++은 그렇지 않지만 gcc의 경우에는 원래 그것이 정의되어 있는 <sys/types.h>를 가져와야지만 컴파일 에러가 안 나기 때문에 같은 소스로도 다른 플랫폼에서 빌드가 되지 않기 때문이다.

 

그런데 이제 64비트 컴파일러 시대가 왔다. ‘16비트 컴파일러 -> 32비트 컴파일러때만큼의 큰 장점은 없기 때문에 그다지 실감은 나지 않는다. 하지만 언젠가 올 미래에는 32비트 보다 더 큰 비트의 운영체제만 존재할 때가 올 것이고 그것 때문에 size_t ptrdiff_t를 다시 고려하게 되었다. 실제로 더 빨리 내가 도입해야 할 것은 ptrdiff_t 쪽이며 그 동안 32비트를 가정하고 포인터를 다루었던 많은 부분들이 다시 리뷰가 되어야 한다.

 

내 생각엔 이 두 개의 타입은 예전부터 언어의 예약어로서의표준이 되어야 하지 않았나 생각된다.

Posted by 안영기

2009/03/15 10:16 2009/03/15 10:16
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/11

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

NULL에 대해

unsigned char* p = NULL;

이라는 코드는 특정한 헤더를 include하지 않는 이상은 컴파일 에러가 나는 코드이다. 하지만 우리 눈에는 코드가 아주 자연스럽게 보인다. 게다가 C에서는 0 아닌 NULL 쓰는 습관을 길러야 한다고 이야기 해왔고, 일부 기고 글에서는 무효화된 포인터가 0이라는 것은 스펙에 정의되어 있지 않으므로 항상 컴파일러가 제공하는 헤더에 정의된 NULL이라는 값만 써야 한다는 주장도 있다. 그리고 실제 컴파일러도 NULL 정의된 주소 값에 대해서는 일반 값과는 조금 다른 동작을 한다고도 알려져 있다. (casting 관련된 경우)

vc++ 정의된 stdlib.h 정의된 NULL 값을 보자. (Linux gcc라면 /usr/include/lunux/stddef.h 있다)

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

(최신 버전의 g++에는 __null 추가된 같긴 하지만 모든 컴파일러가 __null 지원하는 것은 아니므로 일단은 예외로 하겠다)

Pascal 경우에는 nil이란 예약어가 있어서 언어적으로 0과는 구분을 있게 해주었고 서로 섞어 없도록 문법적으로 막아 놓았다. 하지만 C++ 경우에는 #define 값마저도 0 동일하다. C++ 정상적인 프로그래밍 언어라면 #include 하나 없이도 코딩이 가능해야 한다. (OS API IO등의 디바이스 제어와 관련된 부분은 제외하고) 여기서 우리는 #include 사용해서 NULL 정의를 불러 것이냐,
니면 암묵적인 NULL 통용되는 0 사용할 것이냐는 문제에 빠진다.

문제에 대한 답은 없지만, 나의 경우에는 0 사용하는 것으로 결정을 했다. 클래스 헤더 정의에서 포인터형의 멤버 변수가 있고 그것을 생성자 등에서 초기화 해야 , 그것을 위해서 때문에 #include 쓰고 싶지 않기 때문이다. 또한 순수 가상 함수를 정의하기 위한 때에도 같은 이유로 ‘= 0’ 사용한다.

Posted by 안영기

2009/03/15 07:24 2009/03/15 07:24
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/10

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

printf()의 출력이 이상하다?!

예전에 나와 같이 일하던 후임 중에 한 명이 어떤 문제를 가지고 왔다. 타겟 디바이스에서 디버깅 하려고 printf()를 사용했는데 아무래도 원하는 결과와는 다르게 나온다는 것이다. 결국 VC++에서도 동일한 문제가 나온다는 것을 확인해서 다음과 같이 문제를 간략화 시켰다.
코드
struct
{
int* a;
int* b;
int* c;
} a = {0, 0, (int*)1};

printf(
"%d, %d, %d\n", a.c, a, a.c);
결과
1, 0, 0
a.c와 a와 다시 a.c의 내용을 출력하는 예제이다. 분명 코드 상으로도 첫 번째 파라미터와 세 번째 파라미터는 모두 a.c로 동일하다. 그런데 결과는 1과 0으로 서로 다르게 나왔다.
아마도 쉽게 실수 할 수 있는 부분으로 생각되는데, 실수 하기는 쉬운데 반해 그 실수를 찾는데는 굉장히 힘들게 될지도 모르겠다.

Posted by 안영기

2009/02/23 00:10 2009/02/23 00:10
Response
0 Trackbacks , 3 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/9

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

Endian의 고려

자신이 영원히 MS Windows에서 코드를 만든다면 endian은 전혀 신경 쓰지 않아도 된다. 하지만 그렇게 만든 코드는 항상 little endian 전용이라는 꼬리표가 붙어 다녀야 제대로 된 것이다.

코드

unsigned long aaa   = 0x01FF0002;
unsigned char* pCh  = (unsigned char*)&aaa;
unsigned short* pWd = (unsigned short*)(pCh+1);
printf("+++++ %x, %x\n", *pCh, *pWd);

위의 코드는 endian이 전혀 고려되지 않은 코드이므로 일반적인 목적에서는 잘 못 만들어진 코드이다. 그래서 그 결과를 실제로 돌려보면 다음과 같다.

Little endian의 결과

+++++ 2, ff00

Big endian의 결과

+++++ 1, 00ff

Little endian의 결과 (ARM 컴파일러)

+++++ 2, 3d8f

Little endian과 big endian의 결과는 예상한 대로 서로 다르게 나타났다. 원래 메모리의 구조가 그런 것이니 이렇게 나오는 것이 맞다. 그렇기 때문에 위의 코드처럼 프로그램을 만들면 그 코드는 특정 endian에만 적용되는 코드가 되는 것이다.

그리고 여기서 말하고자 하는 것은 이것말고 또 하나가 있다. 제일 마지막에 나온 ARM 컴파일러의 little endian의 결과이다. 같은 little endian이라도 해도 chip-set이나 컴파일러가 달라지면 그 결과가 달라진다는 것을 말하기 위해서 마지막의 결과도 하나 추가했다.

ARM의 경우에는 3d8f라는 전혀 엉뚱한 값이 나타났는데 이 값은 그 결과를 예상할 수 없는 값이며 항상 바뀔 수 있다. 이런데 이 결과는 문제가 없다. 왜냐면 ARM 컴파일러의 매뉴얼에서는 이 문제에 대해서 확실히 언급을 하고 있기 때문이다. (각 자료형에 대한 align 문제이며 이것은 ARM의 동작과 관련된 문제이다) 그래서 비록 자신이 사용하는 컴파일러가 ARM용이 아니라고 해도 범용적인 코딩을 한다고 생각한다면 이런 것까지 다 고려해야 한다.

그래서 결론을 이야기 하자면, endian을 항상 고려해서 코딩을 해야 하며 모든 칩에서 호환이 가능한 문법으로 접근하자는 것이다.

Posted by 안영기

2009/02/22 23:53 2009/02/22 23:53
Response
0 Trackbacks , 4 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/8

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

g++의 버그

프로그램 개발자는 컴파일러를 의심하면 안된다. 제일 먼저 자신 탓을 하고, 하드웨어의 특성을 의심하고, 그것도 문제가 아니라면 그 때야 컴파일러를 의심해 보아야 한다.

그런데 수 많은 버그들과 씨름하다보면 가끔씩 컴파일러를 의심해야 할 때도 있다. 특히 변방의 열악한 컴파일러라면 그런 일이 좀 많긴하다. 그런데 이번에는 g++에 대해서 이야기 하고자 한다.

소스

#include <stdio.h>

int main()
{
unsigned char buffer[2] = {0, 0};
unsigned char* pByte = buffer;

*pByte = 1 + *pByte++;

printf("%d, %d\n", buffer[0], buffer[1]);

return 0;
}

이것의 결과는 어떨까. 나는 2개의 g++ 버전으로 테스트를 해보았다.

g++ 4.0.1의 결과

% g++ --version
g++ (GCC) 4.0.1 (Debian 4.0.1-2)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

% g++ q.cpp
% ./a.out
1, 0
% g++ q.cpp -O3
% ./a.out
1, 0

g++ 3.4.4의 결과

$ g++ --version
g++ (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ q.cpp
$ ./a.exe
1, 0
$ g++ q.cpp -O3
$ ./a.exe
0, 1

확실히 뭔가 이상하다. 4번의 실행 결과는 모두 같아야 하는데 마지막 하나는 결과가 다르다. x86과 MIPS와 ARM의 컴파일러가 서로 결과가 다른 것은 그나마 자주 있는 일인데, 같은 x86인데도 불구하고  동일 컴파일러인데도 버전이 달라지면서 결과가 달라진다든지 최적화 옵션에 따라 결과가 달라진다든지 해서는 안될 것이다.

이 문제가 컴파일러를 만든 쪽에 보고가 된 것인지 아닌지는 알 수가 없지만, 하여간 나는 이 문제 때문에 며칠을 날려 먹었던 것이다. (x86 vs. ARM의 경우에는 컴파일러 특성으로 결과가 달라지는 것은 굉장히 흔한 경우이다. 다음 기회에 이것도 한 번 다루겠다.)

Posted by 안영기

2009/02/22 23:22 2009/02/22 23:22
Response
0 Trackbacks , 2 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/7

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

« Previous : 1 : 2 : 3 : 4 : 5 : Next »

블로그 이미지

Tizen과 GP2X WIZ와 CAANNO와 bada용 게임 개발을 하자

- 안영기

Notices

Archives

Authors

  1. 안영기

Recent Trackbacks

Calendar

«   2017/10   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

Site Stats

Total hits:
159251
Today:
5
Yesterday:
14