« Previous : 1 : ... 126 : 127 : 128 : 129 : 130 : 131 : 132 : 133 : 134 : ... 215 : Next »

<날개셋> 한글 입력기는 도대체 왜 만들어도 만들어도 또 만들 게 끝도 없는 걸까? 미치겠다. ㅠ.ㅠ 이거 좀 진지한 고민거리이다. 누가 이 마약 같은 코딩의 노예계약으로부터 나를 좀 해방시켜 줄꼬.

난 기술을 매우 긍정적으로 보지만, 한편으로 IT 쪽은.. 이제 어지간히 만들어질 거, 나올 건 다 나오고 한계에 도달하지 않았나 하는 회의감도 어느 정도 갖고 있다. Windows도 그렇고 Office도 그렇고.. 소프트웨어 업그레이드의 여파가 이제 예전만 하지 않다.

그러나 <날개셋> 한글 입력기에 관한 한은 상황이 다르다. 여전히 만들어 질 거, 나올 것들이 다 완성된 상태가 아니다. 이건 긍정적인 상태라고 해석해도 될 것 같다.
이 글에서는 <날개셋> 한글 입력기 7.4에 대해서 미처 제대로 공지가 안 되었던 변화 사항과 다음 버전 개발 근황 등을 전하도록 하겠다.

※ 7.4 버전의 잠수함 패치 내역

1.  고급 입력기의 사용자 정의 조합은 이제 언제나 '일반 문자' 타입의 날개셋문자만을 인식한다. 한글 타입(두벌식, 세벌식 등)의 날개셋문자를 0x11??대의 글쇠로 자동으로 인식하는 기능은 없어졌다.
이것은 동작 방식의 간결화를 위해 취해진 조치이다. 한글 자모나 글자를 이용하여 사용자 정의 조합을 만드는 것은 7.4의 고급 입력기에서 추가된 '한글 출력 치환' 기능으로 구현해도 된다. 더 전문적인 대체 기능이 생겼다.

2. 기본 입력기의 글쇠배열 수식에서 이제는 A와 C 변수가 제공되지 않는다. 이것은 사실 디자인상의 실수에 가까운 잉여일 뿐이었다.
글쇠가 눌러질 때 Alt 키가 눌러져 있으면 A에, Ctrl 키가 눌러져 있으면 C에 nonzero 값이 들어왔다. 그러나 7.4부터는 기본 입력 스키마의 기본 94개 글쇠는 언제나 Alt, Ctrl이 눌러져 있지 않을 때만 동작하게 동작이 바뀌었으며 해당 변수는 제공하지 않는다. Alt/Ctrl까지 동원해야 하는 복잡한 글쇠 조합은 고급 입력 스키마로 구현하면 되고, 또 기본 입력 스키마에도 그런 사용자 정의 글쇠 배당 기능이 6.5 버전에서부터 따로 추가되었으므로 이를 활용하면 된다.

지난 7.4 버전은 긴 시간 동안 한글 입력 관련 기존 코드들을 싹 정리하면서 각 개체와 계층들의 역할을 재정리하고 프로토콜도 다시 설계했다. 즉, 리팩터링의 비중이 컸다. 그러면서 이런 미세한 기능들은 좀 예고 없이 변경해도 여파가 별로 없겠다 싶은 것들을 과감하게 뜯어고쳤다. 그랬는데 본인은 <날개셋> 한글 입력기 헤비 유저들의 창의성을 너무 얕잡아 봤던 듯하다.

7.4의 공개 직후에, 잠수함 패치 때문에 예전에 되던 기능이 갑자기 안 되어서 불편을 겪으신 분께 사과드리며, 앞으로는 이런 변화는 충분히 예고를 드리도록 노력하겠다.
특히 고급 입력 스키마의 새 기능을 적극 사용하면서 여러 질문과 버그 신고를 해 주신 김 기윤 님께 감사드린다.

※ 다음 버전 개발 근황

7.4는 큰 버그 없이 잘 만들어진 듯하다. 딱 이 정도 만들어졌을 때 커트를 하여 새 버전을 내놓은 것도 매우 적절했다.
새로 추가된 고급 입력 스키마에서 이것저것 미흡한 점과 개선할 점들이 보이지만 그건 시간과 여유의 부족으로 인해 애초에 고려를 못 했던 부분들이다. 새 기능으로 인해 기존 기능에서 예기치 못한 오동작이 발생한다거나 프로그램의 안정성과 관련된 치명적인 버그가 생긴 것은 없다.

7.4의 다음 버전은 7.5로 계획하고 있다. 7.4를 마무리 지으면서 나머지 잔여 기능들은 하반기에 나올 다음 버전을 기약하기로 그때부터 이미 결정을 해 놨다.
다음 버전의 개발 방향은 (1) 7.4에서 미처 못 끝낸 입력 엔진 리팩터링과 개선, (2) 고급 입력 스키마의 기능 마저 구현, (3) 기타..로 나뉜다. 다만, 이것저것 넣고 싶은 기능들을 다 구현한다면 변화량이 7.5 수준을 초과할지도 모른다.

(1) 고급 입력기의 기능을 활용하고 나면, 두 글자 이상 길이의 조합을 만드는 게 가능해진다. 그러나 조합 중에 C0|0xD (앞쪽으로 조합 중단) 같은 특수글쇠를 집어넣어 보면, 현재는 정확하게 조합의 앞에 cursor가 놓이는 게 아니라 조합의 뒤에서 한 글자 앞에 cursor가 놓이게 된다. 기본 입력기의 기능만 활용해서 한글 한 글자만 조합 중일 때에야 이런 동작 방식이 문제가 없지만, 범용성 면에서 이런 동작 방식은 문제가 있다.

이렇게밖에 할 수 없는 것은 내부적으로 여러 한계가 있기 때문인데, 이 한계를 극복하는 작업을 7.4에서 완전히 마무리 짓지 못했다. 그래서 다음 버전에서는 이를 지체없이 이어서 진행할 예정이다.

또한, 한글로부터 입력 순서를 찾아내는 알고리즘, 인접한 두 한글의 연속 입력 가능 여부를 판별하는 알고리즘을 처음부터 깔끔하게 다시 작성할 예정이다. 지금 작성된 코드는 긴 세월이 흐르면서 나중에 추가된 특수 도깨비불 규칙, 종성 지향 두벌식, 오토마타의 O 변수 같은 복잡한 기능들을 정확하게 반영하여 처리하지 못하며 구조적으로 확장하기도 어려운 형태이다.

주어진 입력 설정으로부터 최적의 한글 입력 sequence를 찾는 알고리즘은 한글 입력기가 제공할 수 있는 가장 유용하고 멋진 자동화 기능이므로 올여름에 심혈을 기울여 재개발을 할 것이다.
뭐, 이것 말고도 지금 모든 내역을 밝힐 수 없는 다른 리팩터링 작업들도 남아 있음.

(2) 고급 입력 스키마에 아직 숙제로 남은 여러 미흡한 기능들을 개선하고, 본격적으로 한글 동시치기와 관련된 추가 옵션들을 구현할 예정이다. 세벌식 자판도 직전 한두 타를 아주 빠르게 누른다거나 하면 조합 중이던 자모가 다음 글자로 넘어가는 '도깨비불' 현상이 발생할 수 있게 된다.

(3) 이것도 모든 내역을 당장 밝힐 수는 없는 여러 이슈들이 현재 존재한다. 아, 입력 패드와 관련된 내용을 잠시 후에 언급하도록 하겠다.

한편, 타자연습은 다른 특이점은 없고 새 연습글들을 허겁지겁 추가하다 보니 오타가 생각보다 많이 발견되어 이걸 고쳤다. 버전 번호를 바꾸지는 않을 것이고, 입력기 새 버전이 나오는 날에 타자연습을 동일 버전으로 다시 배포할 생각이다. 그렇기 때문에 기존 3.4 사용자라면 지금 쓰는 타자연습을 제거한 후, 새 3.4를 받아서 다시 설치해서 사용하시면 될 듯하다. 연습글의 오타 신고는 지금까지 박 철현 님께서 가장 열성적으로 해 주셨다.

※ 입력 패드의 버그 수정

<날개셋> 한글 입력기의 구현체들 중 입력 패드는 7.11에서 7.4로 넘어가는 그 격변기에도 큰 변화가 없었으며, 얘는 앞으로 거의 건드릴 일이 없을 거라 여겨졌다.
그러나 다음 7.5 버전에서는 이 프로그램과 내부 hook DLL이 정말 오랜만에 좀 고쳐질 예정이다.

예전에 외부 모듈은 Excel이나 Paint.NET 같은 프로그램에서 한글을 처음 입력할 때 첫 타 조합이 끊어지거나 덧나는 등 자잘한 문제가 있었다. 엄밀히 말하면 내 프로그램의 로직에 문제가 있긴 하지만, 그 프로그램들이 또 좀 특이하게 동작을 해서... 서로 조심을 안 해서 발생하는 문제였다.

그래서 외부 모듈은 한동안 특정 프로그램에서만 인위적으로 다르게 동작하는 예외 로직을 넣어서 문제를 피해 갔었으나, 지난 7.4에서는 오랜 연구 끝에 그 문제를 드디어 완벽하게 해결했다.
그러나 그 방법이 외부 모듈 말고 입력 패드에는 적용되지 않아 있었다. 여전히 Excel에만 예외 로직이 적용되어 있었으며, Paint.NET 같은 다른 프로그램에서는 글자가 덧나는 문제가 남아 있었다. 단지 입력 패드는 편집기나 외부 모듈보다 훨씬 덜 쓰이는 잉여 프로그램이기 때문에 문제의 심각성이 덜 부각되었을 뿐이다.

그러다가 이번에 입력 패드에까지 새로운 해결책을 적용하여 그 문제를 해결했다.
원래 입력 패드는 hooking을 이용하여 변칙적인 꼼수를 부리며 동작하는 위험한 프로그램이기 때문에 이 문제는 외부 모듈만치 깔끔하게 해결하기가 어려웠다. 이 문제를 해결하느라 다른 부작용(side effect)이 생기지는 않았는지를 아주 꼼꼼하게 테스트해야 했으며 이 과정이 대단히 힘들었다.

또한, '한손 입력기'처럼 내부적으로 독자적인 문자 생성기를 가진 도구를 사용했다가 닫은 뒤에 '화면 키보드' 같은 다른 도구로 문자 입력을 시도했을 때 프로그램이 죽는 문제를 해결했다. 늘 나타나는 현상이 아니어서 그저 그러려니 싶었는데.. 확실하게 코딩 실수가 있는 걸 발견했다. 이 두 가지 버그가 현재 해결되었다.

system hook 프로그래밍을 해 본 분들은 아시겠지만, hook을 사용하는 프로그램이 hook을 해제하고 종료한 뒤에도 어찌 된 일인지 그 hook DLL은 오랫동안 메모리에서 완전히 제거되지 않고 남아 있는 경우가 많다. 그래서 그 hook DLL의 소스를 고쳐서 다시 빌드를 하려 해도 덮어쓰기가 안 되고 진행이 안 되는 경우가 많다.

자잘하게 코드 한두 군데만 고친 뒤 결과를 확인하려고 하는데 매번 운영체제 로그인을 다시 해서 상태를 초기화해야 하니, hook 개발은 IME 개발보다도 더 불편한 애로사항이 있었다. IME는 그래도 프로그램만 확실히 종료하고 나면 업데이트가 안 되는 불편은 없기 때문에 말이다. 예전에 XP/Vista 시절에는 명령 프롬프트 디버깅을 한 뒤에는 conime.exe를 매번 죽여 줘야 해서 불편했지만, 그건 7부터는 개선됐다.

아무튼 본인으로서는 문제를 최대한 해결하여, 지금 동작이 예전의 문제를 해결하면 해결해서 더 낫게 만들면 만들었지, 최소한 예전보다 상태를 더 '나쁘게' 만든 것은 없음을 확인했다. 말은 이렇게 했는데 또 버그가 발견되면 그러면 할 말이 없긴 하지만...

여담인데, Internet Explorer의 웹페이지 내부에 있는 폼에다가 입력 패드로 문자를 입력해 보면,
IE 10까지는 조합이 일반적인 IME로 한글을 입력할 때와 마찬가지로 본문에다 네모 사각형 모양으로 제대로 생긴다. 그러나 유독 IE 11부터는 조합이 그렇게 처리가 안 되고 마치 IME-aware하지 않은 프로그램처럼 프로그램 밖의 조합 창에 따로 생기는 형태로.. 시각적인 피드백이 좀 불편해졌다. 어째 이런 것에도 미세한 변화가 생겼다.

※ 기타 공지

1. 다음 버전에서는 문자 생성기를 가리키는 명칭에 날개셋이라는 단어가 빠지고, 입력 스키마의 명칭과 마찬가지로 그냥 빈 / 기본 / 고급이라는 3단계 수식어만 붙을 예정이다. '빈 입력기, 기본 입력기, 고급 입력기'.
날개셋이라는 이름이 왜 지금까지 있었느냐 하면, 오토마타라든가 각종 특수글쇠처럼 <날개셋> 한글 입력기의 가장 중요한 핵심 기능들이 구현된 계층이 문자 생성기이기 때문이다. 쉽게 말해 상징적인 의미 때문이다. 하지만 그건 군더더기라 여겨져서 다음 버전부터는 빼게 되었다.

2. <날개셋> 한글 입력기가 버전을 매기는 방식은 통상적인 소수점과 완전히 동일하다. 가령, 버전 7.4와 7.40은 동일한 표기이며 7.4는 7.11보다 더 높은 버전이다. 다만, 공식적으로는 끝의 0은 생략하여 7.40 대신 7.4라고 표기하는 것을 권장· 선호한다.

3. 그리고 이것도 한 번쯤 언급할 필요가 있어서 입장을 확실히 밝히고자 한다. <날개셋> 한글 입력기는 브랜드 이름을 지금까지 less than과 greater than 부호로 감싸는 이상한(?) 관행이 존재해 왔다. 이것은 세벌식 최종 글자판이 ()와 <>를 아랫글쇠로 입력할 수 있다는 것에 착안하여 별 생각 없이 붙이게 됐는데..
반드시 강요는 안 한다. 파일 이름이나 HTML 태그 같은 상황에서 <>를 붙이기가 대략 난감할 때는 얼마든지 생략해도 된다. 영문 표기에서도 당연히 생략.
하지만 한글로 full name을 공식 표기할 때는 <>를 넣는 것을 원칙으로 삼고자 한다. ㅎㅎ 여기에도 이런 내력이 있는 셈이다.

4. 진짜 마지막으로... 간단한 내용이지만 최근에 문의를 한 분이 있어서 또 공지하도록 하겠다.
입력기와 타자연습을 모두 사용하시는 분이라면, 두 프로그램을 모두 최신 버전으로 업데이트할 것을 강력하게 권한다.

타자연습도 실행에 필요한 최소한의 파일들은 자체적으로 모두 갖추고 있으며 입력기와 독립적으로 동작하는 게 가능은 하다. 그러나 입력기와 타자연습이 서로 API 호환이 되지 않으면 타자연습은 입력기의 모든 기능을 100% 활용할 수가 없게 된다. 특히 플러그 인을 사용할 수 없게 되기 때문에 고급 입력 스키마나 고급 입력기 같은 기능을 사용한 입력 설정이 무용지물이 된다. 반드시 업데이트를 해야 한다.
이번에 타자연습은 3.31 이후 거의 1년 반 가까이 버전업이 없다가 3.4로 업데이트됐기 때문에 문의가 들어올 만도 했던 것 같다.

Posted by 사무엘

2014/07/10 19:32 2014/07/10 19:32
Response
No Trackback , 5 Comments
RSS :
http://moogi.new21.org/tc/rss/response/983

노트북 PC에서 가장 흔하게 발생하는 잔고장의 양대 산맥은 (1) 액정 화면 접촉불량과 (2) 키캡 빠짐이라 해도 과언이 아닐 것이다.

본인이 개인용 노트북 PC를 사용한 지가 15년이 넘었고 지금 쓰는 맥북은 제 5대 컴퓨터인데,
예전에 쓰던 노트북들은 쓴 지 1년 남짓 되면 저런 잔고장이 어김없이 발생하곤 했다.
물론, 언제나 새 노트북만 쓴 게 아니라 중고나 준중고를 쓴 것도 있기 때문에, 품질이 원래부터 안 좋아서 그랬던 것일 수도 있다.

(1)은 화면을 편 각도에 따라서 붉은 세로줄이 나타났다가 사라진다거나, 화면이 아예 꺼진다거나 하는 등 굉장히 성가신 증상이다. 이것 때문에 서비스센터 들러서 수리 받느라 신경 쓰이고 시간· 돈이 낭비되는 것도 과거엔 상당한 수준이었다.

(2)도 노트북 키보드가 데스크톱 PC 키보드보다 약해서 발생하는 고질적인 문제인 듯.
자주 누르는 편인 화살표, 엔터, space, shift 같은 게 잘 빠졌으며 가끔은 문자 키가 빠지기도 했다. 키캡이 없어도 해당 키를 누르는 것 자체는 가능하지만, 빠른 타자와 원활한 컴퓨터 사용에는 애로사항이 꽃핀다.
빠진 키캡 한두 곳만 수리가 되지는 않는 경우가 많다. 그래서 키캡이 대여섯 개쯤 빠질 때까지 컴을 더 쓰다가, 나중에 한꺼번에 키보드 기판을 교체하곤 했던 것 같다. 돈 몇만 원 정도는 깨진다.

그런데.. 지금 쓰는 맥북은.. 쓴 지 2년이 넘었지만. 위의 잔고장이 지금까지 전혀 발생한 적이 없다. 엔터 키가 약~간 달랑달랑거리긴 하지만 그래도 키캡이 완전히 빠진 건 없다. 잡느님의 손길이 담긴 품질 덕분인 걸까? 놀랍다.
맥북은 한번 병원 치료를 받으면 일반 놋붉에 비해 수리비가 작살나게 깨진다는 게 겁나긴 했었지만, 아직까지 A/S를 받을 일 자체가 전혀 없었다.
(참고로 난.. 흔들리는 교통수단 안에서도 쓰고 몇 번 떨어뜨린 적도 있고, 노트북 PC를 시도 때도 없이 험악하게 혹시시키며 쓰는 편이다.)

따라서 애플케어를 구입 안 한 게 현재로서는 결과적으로 이익이었다.
난 비록 맥북으로도 95% 이상의 시간은 맥OS가 아닌 Windows만 쓰며 지내지만 맥북의 이런 품질은 만족스러우며 인정할 만하다.

다만, 세월 때문인지 배터리 용량은 예전보다 확실히 줄어들었다. 2시간 남짓이면 간당간당하다. 배터리는 아직 구경도 못 해 봤다.
그리고 얼마 전엔 맥북을 쓴 지 2년 3개월 만에 처음으로 기능 고장을 경험했다. 본체나 LCD 쪽은 아니고, 전원 어댑터가 문제가 발생했다.

여기저기서 전선의 피복이 슬슬 벗겨지면서 속의 금속선들이 드러나 보이기 시작했다. 벗겨진 부분에다가는 테이프를 감았으며, 노출 부위 때문에 감전이나 화재 사고가 날까 두려워서 잘 때나 부재 중일 때는 전원 플러그를 빼 두기 시작했다.
그러더니 나중엔 컴퓨터 본체와 연결하는 목덜미 부분이 너무 너덜너덜해진 나머지 거의 두 동강 나다시피하면서 결국 단선됐다. 전원을 연결해도 본체에 전원 공급이 되지 않기 시작했다. 컴퓨터 본체는 이제 2시간짜리 시한부 인생으로 전락했다.

어댑터 전선에 피복이 벗겨지면서 고장이 이런 식으로 발생하는 노트북 컴은 맥북이 처음이다. 그런데 다른 맥북/아이폰 사용자에게 물어 보니, 애플 제품은 그런 식으로 전원 어댑터 내지 충전기가 망가지는 건 생각보다 흔한 일이라고 한다.

어댑터 자체는 이상이 없고 전선만 망가진 건데 어째 물건을 재활용할 수는 없나 궁금하다. 물론, 콘센트 쪽 전선이 아니라 컴퓨터에다 꽂는 쪽의 전선이다 보니 어댑터와 분리가 가능하지도 않고 가능하지는 않을 것 같다.

지금은 어댑터를 새로 구입해서 상황을 마무리 지었지만, 약 3~4일 동안 내 컴을 못 쓰면서 좀 불편하게 시간을 보냈다. 다음부터는 좀 불편하더라도 컴퓨터 본체와 어댑터 선이 언제나 같은 높이와 평행한 각도가 유지되게 해 놓고 써야겠다. 목덜미 부근엔 수축 튜브를 감아 주고, 전선을 둘둘 감아서 가방에 넣는 것도 굉장히 조심해서 해야 할 것 같다.

* 다음은 여담.

1. 맥 OS가 의외로 굉장히 유용한 경우가 있는 걸 본인이 얘기한 적이 있나 모르겠다. 바로 학교 안에서이다.
Windows의 경우 컴퓨터의 속도를 한 반쯤 깎아내리는 엄청난 백신, 보안 솔루션 등을 강제로 설치해야만 교내 무선 인터넷 이용이 가능한 반면, 맥 OS는 그런 것 전혀 없이도 바로 인터넷 이용이 가능하기 때문이다. 아주 편리하고 좋다.

2. Windows 진영에서는 Metro라는 이름을 안 쓰는 게 마음에 안 들던데, 애플 진영에서는 매킨토시로도 모자라서 Mac이라는 이름까지 왜 빼 버렸나 궁금하다.. 자기 정체성을 가장 잘 분명하게 보여 주는 명칭을 빼 버리고 그냥 OS X...;;;

3. 그러고 보니, 플래시가 깔려 있지 않은 맥 OS의 사파리 브라우저에서 유튜브 동영상이 나오고 있어서 깜짝 놀라서 살펴봤더니.. 말로만 듣던 HTML5 기반 동영상이다. 우와~ 물론 비스타+IE9 구닥다리에서 실행해 보니 여전히 플래시다. 브라우저에 따라 기술을 알아서 판별하는 듯하다.

솔직히 플래시든 뭐든 인터넷으로부터 패킷을 받아서 하드웨어 가속으로 동영상을 틀어 준다는 기본 원리는 똑같다. 단지, 동영상을 해독하고 재생하는 기계어 코드가 예전에는 플래시 ActiveX라는 일종의 private한 영역에 있었던 반면, 이제는 그게 통일된 규격으로 웹브라우저에 있다는 차이만이 존재할 뿐이다. 웹 표준은 기술 자체가 아니라 기술을 담는 그릇의 규격에 대한 논쟁인 것이다.

Posted by 사무엘

2014/07/08 08:29 2014/07/08 08:29
,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/982

근황 + 컴퓨터 음악 이야기

올해 상반기는 박사 첫 학기 진학과 <날개셋> 한글 입력기 7.4 완성이라는 본인의 개인사와는 대조적으로, 분위기가 은근히 우울했다.
월드컵 축구 경기는 기대를 저버리는 졸전 끝에 별 재미를 못 봤고, 신촌 동성애 퍼레이드에다 어째 1993년에 벌어진 것과 비슷한 패턴의 사건· 사고가 두 건이나 벌어졌다. 세월호(1993년의 서해 페리호), 그리고 총기 난사+무장 탈영(1993년의 임 채성 무장 탈영 인질극) 말이다. 정치판에서 돌아가는 큼직한 사건들은 좌파와 우파 성향 모두에게 최악의 실망만을 안겼다.

뭐 어쨌거나.. 이번 학기에 본인은 아직 프로그램 개발에 더 전념하려고 수업은 2개만 들었다. 언어학 문법 수업은 배경 지식이 부족하다 보니 확실히 어려웠다. 그래도 다음 학기에 프로그래밍 언어와 관련된 수업을 들으면서 경험을 서로 대조해 보면, 자연어와 인공 프로그래밍 언어가 개념적으로 어떤 관계가 있는지를 조명할 수 있을 것 같다.

다음으로 학기 초부터 기대했던 컴음악은 어려운 한편으로 재미있었다.
다른 학생들이 텀 프로젝트를 발표한 걸 보니 모바일 또는 웹으로 간단한 미디 음악 시퀀서를 만든 경우도 있고, 미디 데이터를 일정 규칙대로 변조하거나 climax를 찾는 알고리즘을 연구하기도 했다.
그 담당 교수님의 연구실에 들어가 있는 학생들은 여러 이미지와 여러 음악들을 분위기에 맞는 것끼리 서로 짝지어 주는 솔루션을 주로 내놓았다.

나도 처음에는 멜로디로부터 chord를 자동으로 매긴다거나 다른 감정 같은 의미를 읽어 내는 프로그램을 생각하고 있었으나.. 곧 단념했다. 그런 것도 없는 곡을 새로 만드는 것만큼이나 엄청 어렵고 창의적인 일이라는 걸 곧 인지했기 때문이다.

결국, 컴음악 시간에는 이 기회를 이용해 죽이 되건 밥이 되건 자동 작곡을 하는 프로그램을 만드는 걸로 방향을 선회했다. 복잡한 요소들 싹 다 제끼고 오로지 초등학교 음악책에 나오는 동요 급의 간단하고 짤막한 단음 멜로디를 생성하는 것.

음악이라는 게 어느 정도는 무질서하고 무작위한 요소가 있지만, 그 뒤부터는 정말 인간의 언어만큼이나 극도로 예전 문맥에 의존적이고 체계와 질서가 있어야 한다. 그게 없이 그저 rand()의 결과대로 멜로디와 박자를 뿌리면 그건 음악이 되지 않고 아무 호소력이나 메시지, 시너지 효과가 안 나오는 횡설수설 노이즈밖에 만들어지지 않는다.

연구하면 할수록 음악도 마치 문장을 구문 분석하듯이 계층이 존재한다는 걸 알 수 있었다. 각 마디 안의 음표들은 일정 chord 범위에 드는 한도에서 생성되는데, 그 chord가 바뀌는 규칙은 또 다른 상위 계층에 따라 정해지고, 그 계층의 상위 계층은 또??

맨 처음엔 박자를 재귀적으로 무작위 생성하는 것부터 해 봤다. 음색이 들어간 음악이 말 그대로 색, 컬러 그림이라면, 박자는.. 그냥 흑백 그림에 가깝다고 하겠다. 박자도 생각보다 가짓수가 많았으며, 취사선택을 잘 해야 했다.

2 1 1 2 1 1
8
3 1 4
4 2 2
3 1 4
8
2 1 1 2 2
6 2
4 2 2
3 1 2 2
2 2 3 1
8
2 2 2 2
3 1 2 1 1
6 2
3 1 4
8
4 2 1 1
4 2 2
6 2
1 1 1 1 2 2
1 1 1 1 4

아주 공교롭게도, 마지막 두 박자는.. 바로 “노래 시작했다 노래 끝났다 / 그런 노래 없다 다시 불러라”의 박자와 동일하다.. ㅋㅋㅋㅋ 컴퓨터가 그런 박자도 만들어 냈다. 하지만 박자에다가 음색을 입히는 건 훨씬 더 어려운 일이었다.

처음엔 1도 화음에서 시작하고 끝은 언제나 '도'로 끝나고, 주어진 chord와 어긋나는 음은 약박에만 들어가게 하고,
같은 음 반복, 1도씩 증가, 1도씩 감소 같은 인위적인 규칙을 일정 확률로 준 결과, 노이즈보다는 듣기 좋은 멜로디가 종종 생성되었다. 아 물론, Looking for you나 Let it go 같은 퀄리티를 기대해서는 안 되지만..ㅎㅎ

텀 프로젝트를 발표한 후 교수님의 반응은 “(1) 마디별 코드 전환이 부드럽고 꽤 그럴싸하게 작곡이 잘 됐다. (2) 단, 당초 계획만치 참고문헌 내용이나 관련 기존 연구 성과가 반영되지 못한 것은 아쉬움”이었다.

내가 목표했던 퀄리티는 그냥 별 생각 없이 콧노래를 흥얼거리는 수준의 작곡이었다. 그런데 사람은 무작위로 흥얼거린다 해도 결국 예전에 자기가 들어서 기억하고 있는 음악을 변형하는 형태인 반면, 컴퓨터는 그런 경험 데이터가 없이 난수 생성만으로 음악을 만든다. 결국 컴퓨터도 사람에게 듣기 좋은 음악을 만들려면 모방이 필요하며 기존 음악 패턴에 대한 데이터가 아주 없어서는 안 될 것 같다.

이래저래 음악은 탁월한 수리 능력에다가 창의성까지 갖춘 괴수 천재들을 매혹시키기 충분한 분야이다. 리서치 과정에서 Musimathics라는 책을 참고했는데, 저자는 이건 뭐 수학, 전산학에 소리를 물리· 전자공학적으로 분석하는 것까지 완전 다 통달한 천재다. 전자공학의 푸리에 변환도 나오고, 작곡 방법론에서 난수 생성 얘기를 하는 데서는 ACM 논문까지 소개한다.

나 또한 딴 건 몰라도 음악의 위력에 대해서는 Looking for you와 관련하여 할 말이 무진장 많다. 이런 음악 한 곡도 지적 설계자의 치밀한 설계 없이는 만들어질 수 없는데 하물며 이 세상 만물이겠는가 하는 생각도 응당 들었다.

사실, 과거에 마소에서는 미래엔 이렇게 실시간으로 작· 편곡을 하여 분위기에 맞는 음악을 만들어 내는 게임이 등장할 걸로 예상하고 DirectX에다가 미디 기반의 DirectMusic이라는 컴포넌트도 만들었다. 1990년대 말이면 아직 소프트웨어 기반 미디 신시사이저도 흔치 않던 시절이어서.. 하지만 게임 음악 기술은 음표 신호 방식이 아닌 waveform 방식으로 대세가 완전히 바뀌었으며, DirectMusic도 개발이 중단된 흑역사로 전락했다. 아쉽다면 아쉬운 점이다.

다음은 여담이다.

1.
어떤 학생이 자기 결과물을 발표하고 시연하는 중이었는데, 파일을 기록했다는 영문 메시지가 writed라고 뜨고 있었다. 본인은 그걸 보면서 속으로 뿜었다. 우와, 정말 생각도 못 했던 단어다.
그런데 집에 돌아와서 내가 발표했던 PPT 자료를 다시 보니, 나도 ‘결론’을 Conclusition이라고 써 놔 있었다. ㅋㅋㅋㅋㅋ

다들 시간에 쫓기는 상태로, 혹은 밤샘 하고 나서 머리 가동률이 70% 이하로 떨어진 상태로 비몽사몽 발로 영작을 하다 보니 저런 오타들이 나왔는가 보다.

2.
본인은 작곡한 멜로디를 출력할 때 미디 API를 쓴 게 아니라, 과거 BASIC에 존재하던 PLAY문과 비슷한 기능을 하는 함수를 직접 만들어서 썼다. 지정된 음의 주파수에 해당하는 sine wave를 생성해서 오디오로 출력하는 것이다. 난생 처음으로 waveOut*** 어쩌구 하는 함수들을 직접 공부해서 써 봤다.

난 간단한 콘솔 프로그램을 만드는 게 목적이기 때문에 파일 재생 관련 통지를 그냥 callback 함수 호출로 받게 했는데... 뭐가 이상하게 꼬이면서 잘 되질 않았다.
한참을 디버깅 하다가 시간도 부족하고 설마 하는 심정으로 message-only 윈도우를 만들고 통지를 메시지로 받게 했더니.. 모든 문제가 싹 해결되었다. 메시지가 진리. 두 메커니즘의 차이가 뭔지는 잘 모르겠다.

그래픽 애니메이션 출력 때 더블 버퍼링을 하는 것만큼이나, 실시간으로 오디오 데이터를 보내는 것도 더블 버퍼링 기법이 쓰인다는 게 흥미롭다. 관련 코딩을 해 보신 분이라면 이미 잘 아실 것이다.
버퍼 A의 내용이 사운드 카드로 가서 재생되는 동안 미리 버퍼 B의 내용을 보내 놓고 기다리고, 다음으로 버퍼 B가 처리되었으면 다시 버퍼 A에다가 다음 내용을 보내는 것이다.

Posted by 사무엘

2014/07/05 08:36 2014/07/05 08:36
, ,
Response
No Trackback , 4 Comments
RSS :
http://moogi.new21.org/tc/rss/response/981

컴퓨터 화면에 그려진 어떤 물건(주로 사각형 모양)의 경계 테두리에다 마우스를 갖다대면 포인터가 그 경계 테두리와 수직인 방향의 화살표로 변한다. 그 상태에서 마우스를 클릭하여 끌면, 그 물건의 크기를 마우스 포인터가 움직이는 방향으로 변경할 수 있다.
이것은 GUI에서 매우 흔히 볼 수 있는 기능이다. 특히 크기 조절 가능한 창--운영체제가 정식으로 제공하는 GUI 구성요소--의 경우 이런 기능은 운영체제가 non-client 영역에서 알아서 자동으로 처리해 준다.

그런 창이야 운영체제가 처리를 알아서 해 주지만, 대화상자 내부의 임의의 영역에 대해서, 혹은 클라이언트 영역에 내가 그려 주는 임의의 객체에 대해서 이런 처리를 구현하려면 어떻해야 할까? 뭔가 공통된 패턴의 알고리즘을 처리해야 할 텐데 코딩량이 적지는 않으며 왠지 귀찮고 번거로워 보인다.

크기 조절 내지 화면 분할 UI와 관련해서는 다음과 같은 여러 상황을 생각할 수 있다.

1. 한 윈도우 내부에 그려지는 개체의 크기 조절

2차원 벡터 그래픽 프로그램 내지 RAD 툴의 폼 에디터가 정확하게 여기에 속한다. 요즘은 워드 프로세서도 자체적인 벡터 그래픽이나 하다못해 OLE 개체라도 취급하니 마우스를 이용한 크기 조절 기능을 제공해야 한다. 개체를 클릭하면 8군데의 앵커 사각형이 생기며, 경계 아무 곳이라기보다는 그 앵커 사각형을 드래그했을 때 크기 조절이 된다. 다른 곳을 드래그하면 크기 조절이 아니라 이동이 되고. 그리고 요즘 MS 오피스 제품은 회전용 앵커까지 덤으로 제공한다.

비주얼 C++에는 CRectTracker라는 고전적인 클래스가 있어서 마우스 드래그로 임의의 사각형 영역을 화면에다 그리고 마우스가 클릭됐을 때의 일체의 처리를 알아서 해 준다. 이것만 쓸 줄 알아도 상당히 편리한데, 본인은 지금까지 그런 분야의 프로그램을 개발할 일이 없다 보니 실제로 써 본 적은 전혀 없다. 이런 게 있다는 것만 안다.

그리고, 지금도 있나 모르겠다만, 비주얼 C++에는 DrawCli라고 딱 개체 기반 벡터 드로잉과 드래그 드롭, 크기 조절과 이동을 모두 시연해 놓은 걸출한 예제 프로그램이 있다.
학창 시절 나의 친구였던 <비주얼 C++ 완벽 가이드>(김 용성)에도 '트래커'라는 예제 프로그램이 있으니 참고할 것.

사용자 삽입 이미지

참고로, 저렇게 테두리를 그리고 사각형 안의 내용물은 대각선 사선으로 칠하는 건.. embed된 OLE 개체를 외부 프로그램이 수정 중일 때 클라이언트 프로그램이 표시하는 표준 모양이기도 하다.

사용자 삽입 이미지

2. 부모 윈도우가 자식 윈도우를 동적으로 분할하고 관리

규모깨나 좀 있는 문서 편집 프로그램을 보면, view를 분할하는 기능이 있다. 이것은 한 문서 컨텐츠에 대해 뷰 윈도우를 여러 개 둬서 한 컨텐츠를 여러 가지 다른 방식, 다른 위치를 표시할 수 있게 한다. 사용자의 입장에서 매우 편리한 기능이지만, 컨텐츠와 뷰 윈도우가 완전히 일심동체라고 전제하고 만들어져 버린 프로그램이라면 추후에 이러 기능을 추가하기가 쉽지 않을 것이다. MDI 프로그램이라면 아예 별도의 독립된 창을 만드는 기능도 있겠지만 SDI에서는 한 창을 분할하는 것만 가능하다.

이건.. 생각보다 만들기 어려운 기능이다. 경계(splitter) 부분을 마우스로 끌었을 때의 처리도 처리거니와--이를테면 XOR 연산으로 자취를 그렸다가 지우는 것도..--, 내가 무엇보다도 힘들겠다고 느끼는 건 스크롤 바를 자체적으로 따로 만들어서 관리하는 부분이다. 이게 무슨 뜻인지를 설명하자면 이렇다.

Windows 운영체제에는 어떤 윈도우가 자체적으로 스크롤 바를 가질 수 있고, 한편으로 스크롤 바 자체가 별도의 컨트롤로 존재할 수 있다.
윈도우가 자체적으로 갖는 native 스크롤 바는 당연히 운영체제가 모든 처리를 알아서 해 준다. 창의 크기가 바뀌어도 스크롤 바를 자동으로 우측(상하) 내지 하단(좌우)에 배치해 주고, 스크롤을 할 필요가 없어지면 알아서 스크롤 바가 없어지고 그 영역까지 클라이언트 영역이 확대된다.

그러나 splitter가 존재하는 view를 보면, 스크롤 바가 있던 자리의 구석 일부에 창을 분할시키는 앵커가 자리잡고 있다. 이건 native 스크롤 바로 구현 가능하지 않기 때문에 스크롤 바 컨트롤을 따로 만들어서 앵커 밑이나 옆에다 두고, 스크롤 바의 위치· 크기와 관련된 모든 처리를 수동으로 해야 한다. 이 얼마나 복잡하고 손이 많이 갈까? 그러니 MFC가 CSplitterWnd라는 클래스에다 전부 구현해 놨다.

사용자 삽입 이미지

MFC AppWizard에서 '뷰 분할 기능 사용'을 체크하면, 프레임 윈도우는 밑에다 저 splitter 윈도우를 생성하고 걔가 또 자기 밑에다 어떤 view를 생성할지를 따로 지정해 준다. 다시 말해 프레임 윈도우와 view 사이에 splitter라는 중간 계층 윈도우가 하나 또 생긴다는 것이다. 그리고 요놈이 스크롤 바와 앵커의 위치를 관리하고 앵커 드래그에 대한 처리도 담당한다.

사용자 삽입 이미지

내가 MFC의 splitter 윈도우에 대해 꽤 놀란 것은, 분할을 2개씩뿐만 아니라 그 이상도 얼마든지 할 수 있다는 점이다. 위의 그림처럼 가로 3개, 세로 3개를 분할해서 무려 9개나 되는 view 윈도우를 뻥튀기시킬 수도 있다. 가로와 세로의 splitter 중 어느 것 하나의 위치가 바뀌었을 때, 혹은 창 전체의 크기가 바뀌었을 때 splitter가 총체적으로 조율하고 해야 할 일의 양도 그에 비례해서 많아질 것이다.

그런데 각각의 창들이 다 독자적인 가로· 세로 스크롤 바를 갖는 건 아니고.. 위의 스크린샷에 보듯이 한 column에 해당하는 view들은 가로 스크롤 바를 하나 다같이 공유한다. 그리고 한 row에 해당하는 view들은 세로 스크롤 바를 다같이 공유한다. 특이한 점임.

3. 부모 윈도우가 자식 윈도우를 '정적'으로 분할하고 관리

위의 2번과 마찬가지로 부모 윈도우가 자식 윈도우의 분할을 관리하는 경우이긴 한데, 위처럼 성격이 비슷한 윈도우가 아니라 별개의 윈도우를 고정적으로 관리하는 경우를 추가적으로 생각할 수 있다. 처음엔 1개였다가 2개 이상으로 자유자재로 분할되는 건 아니기 때문에, 스크롤 바나 앵커 같은 건 없다.

왼쪽에 트리 컨트롤, 오른쪽에 리스트 컨트롤을 두고 가로로 크기 조절이 가능한 탐색기 같은 프로그램도 좋은 예이고, 그보다 좀 더 복잡한 경우로는 개발자들의 친구인 Dependency Walker가 있다.

사용자 삽입 이미지

Spy++ 같은 프로그램으로 들여다보면, 창 구조가 생각보다 복잡하다는 걸 알 수 있다.
가장 겉에 있는 창은 화면을 상하로 나눈다. 위에 있는 창은 화면을 또 좌우로 나눠서 왼쪽은 모듈 트리 구조가 나오며, 오른쪽은 또 상하로 나누어서 각각 이 모듈이 import하는 심벌들, 그리고 대상 모듈이 export 하는 전체 심벌들이 표시된다.
한편, 아래의 화면은 또 상하로 나뉘어서 위에는 전체 모듈 리스트가 있고 아래에는 메시지 log가 있다.

즉, 한 윈도우에 여러 개의 컨트롤들이 sibling 관계로 대등하게 늘어서 있는 게 아니라, 또 분할 윈도우가 있고 그 아래에 또 분할 윈도우가 자식 윈도우로 있는 형태다. 한 분할 윈도우는 언제나 좌우로든 상하로든 2개의 윈도우만을 담당한다.

이렇게 이분법적으로 접근하면, 제아무리 복잡하게 화면이 좌우 상하로 분할되어 있는 창이라 해도 전체 크기가 바뀌었다거나 할 때 자기가 맡은 두 개의 창만 비율 분배를 잘 하고 나머지는 자가반복적인 재귀 처리에 맡기면 되니 문제가 단순해진다는 장점이 있다.

저런 윈도우가 활용의 자유도가 더욱 올라간다면 아예 별도의 창으로 분리하거나 docking까지 가능해진다. Visual Studio의 각종 보조 윈도우들처럼 말이다. 그건 우리 같은 평범한 프로그래머가 밑바닥부터 할 짓이 못 되며, 이미 있는 GUI 라이브러리의 사용법을 익히는 것만으로도 충분할 것이다. MFC 없이 Windows API만으로 docking toolbar를 구현한 소스를 외국 사이트에서 본 적이 있는데, 가히 근성이 느껴졌다.

사용자 인터페이스라는 건 컴퓨터로 하여금 의미 있는 작업을 하게 만드는 실질적인 알고리즘이 아니다. 없던 걸 처음 시도하여 만드는 게 아닌 이상, 베끼기만 하느라 시간 낭비할 필요는 없을 것이다.

4. 대등한 위상의 윈도우끼리 분할 관리를 해야 하는 경우

어휴, 글을 이렇게 길게 쓸 생각은 없었는데... 마지막 아이템도 언급을 안 할 수가 없구나. -_-;;
자, 지금까지 얘기한 것들을 정리하자면 1번은 그냥 한 윈도우 내부에서 그리기를 하는 것뿐이며, 2번과 3번은 부모 윈도우가 자식 윈도우들의 공간 관리를 하는 경우를 특별히 MFC의 document-view 아키텍처의 예를 들어 소개한 것이다.

그러나 실무에서는 그것만이 전부가 아니다. 대화상자처럼 document-view 아키텍처가 적용되지 않는 창에 대해서도 수평/수직 splitter 같은 물건을 만들어야 할 때가 있다.
예를 들어, <날개셋> 제어판 같은 경우, '분야'를 나타내는 왼쪽의 트리 컨트롤과, 오른쪽의 여타 컨트롤들 사이에 수직 splitter를 둬서, 트리 컨트롤의 폭을 좀 더 넓힌다거나 반대로 좁히는 경우를 생각할 수 있다.
이 경우 splitter는 여타 컨트롤들과 마찬가지로 대화상자 안에 존재하는 여러 자식 윈도우의 하나일 뿐이지 나머지 컨트롤들을 모두 통솔하는 부모 윈도우의 지위는 아니게 된다. Spy++로 들여다보면, 가로나 세로로 길쭉한 고유한 splitter 윈도우가 잡히는 걸 볼 수 있다.

이런 상황에 대해서는 MFC는 딱히 제공해 주는 있는 클래스가 없다. codeguru 같은 데서 splitter dialog 정도로 검색해 보면 예제 소스나 관련 튜토리얼들이 쭉 나온다. 예전에 아주 괜찮은 코드를 하나 구해서 유용하게 쓴 적이 있었는데 지금 다시 검색하려니까 못 찾겠다.

이런 일을 하는 범용적인 클래스를 만들 때 염두에 둬야 하는 사항으로는, 좌우나 상하든 보장해 줘야 하는 최소 크기를 인자로 받아야 할 것이고, 좌우 상하 중 한쪽에다 뒀으면 하는 윈도우를 배열 같은 자료구조로 관리해야 한다. 윈도우 핸들이 아닌 ID로 받으면.. ID로부터 실제 핸들값(HWND)을 얻어야 하는 번거로움이 있지만, 그 컨트롤이 중간에 재생성된다거나 해도 여전히 식별이 가능하기 때문에 범용성이 좀 더 향상된다.

다른 splitter조차 자기의 크기 조절에 영향을 받게 하고 WM_SIZE 메시지에 반응한다면, 아까 Dependency Walker 같은 복잡다단 splitter도 얼마든지 구현 가능하다.
splitter를 구현하려면 당장 크기를 조절하는 것 처리는 둘째치고라도, 창의 크기가 바뀌었을 때 각 분할 화면들의 공간 배분을 어떻게 할지 같은 것도 생각해야 하니 여러 모로 골치가 아픈 건 사실이다.

끝으로 언급하고 싶은 이슈가 있다. 1~4번들은 다 마우스가 클릭되었을 때 캡처를 잡고 마우스 움직임을 추적하다가 버튼이 떼졌을 때 마무리 처리를 한다는 공통점이 있다.
이 경우, WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP을 모두 메시지 맵에다 등록하고 각 상황별 코드를 메시지 핸들러 함수에다 제각기 따로 작성하는 방법을 생각할 수 있지만..

좀 더 능숙한 프로그래머라면, 그런 드래그 드롭 처리 정도면 WM_LBUTTONDOWN에다가 아예 별도의 message loop을 만들어서 거기에다 WM_MOUSEMOVE와 WM_LBUTTONUP에 해당하는 코드를 다 집어넣는 방법을 선택한다. 한 함수에다가 한 기능에 대한 처리를 몰아서 넣는 게 훨씬 더 깔끔하기 때문이다.

Posted by 사무엘

2014/07/02 08:32 2014/07/02 08:32
, ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/980

* 에구. 나 완전 고전 게임 덕후 인증이다. ㅎㅎ

1.
옛날의 액션/아케이드 게임 중에는 주인공을 죽게 하는 각종 트랩들이 적(몬스터)에게도 동일하게 적용되는 게 있고, 그렇지 않은 게 있다. 동일하게 적용되는 게 더 공정하고 현실 고증에 더 충실한 시스템이겠지만, 그 경우 적의 AI를 더 똑똑하게 만들어야 게임성이 성립할 테니 개발자에게는 더 큰 난관이 된다. 안 그러면 적을 정당하게 싸워서 죽이는 게 아니라 AI 헛점을 이용해서 트랩으로 죽이는 꼼수가 너무 횡행하여 게임 밸런스가 무너질 것이다.

이런 한계로 인해 id에서 개발한 둠, 퀘이크 등의 몬스터는 용암이나 화학 용액 같은 데에 들어가도 체력을 잃지 않으며 물에 들어가도 익사하지 않는다. 그 대신 잘 알다시피 자기끼리 팀킬을 벌이는 몬스터 내전(monster infighting)이 있을 뿐이다. 둠에서는 몬스터들이 정말 무식한지라 내전이 정말 잘 벌어졌지만, 퀘이크에서는 몬스터와 주인공 사이에 다른 몬스터가 일직선으로 있을 때는 공격을 안 하게 일말의 AI 개선이 이뤄졌다.

위험한 데이브에서는 몬스터는 트랩 같은 건 쌈싸먹으며 잘만 날아다니고..
과거의 툼 레이더 게임들은 주인공이 혼자 트랩 퍼즐을 풀어야 하는 구역과 몬스터와 싸우는 구역을 완전히 철저하게 분리하여 논란의 여지를 차단한 사례에 가깝다.
Rick Dangerous 2는 이 점에서 독특하다. 몬스터도 미사일, 전깃줄 같은 트랩에 걸리면 얄짤없이 죽을 뿐만 아니라, 이렇게 죽이는 게 전기총(50점), 폭약(100점) 같은 주인공의 일반적인 공격으로 죽이는 것보다 점수도 더 높게 준다(150점).

자, 서론이 너무 길어졌는데.. 페르시아의 왕자는 잘 알다시피 로토스코핑 기법으로 스프라이트를 만들었을 정도로 극도의 현실성을 추구한 게임이다. 악당도 딱히 초현실적인 괴물이 아니라 그저 검을 든 똑같은 인간이며, 이들을 상대로도 가시와 톱날 같은 트랩은 똑같이 동작한다. 악당 역시 트랩에 걸리면 피투성이가 되어 끔살당한다.

악당을 죽이는 방법으로는 (1) 칼 공격으로 HP를 다 깎아서 죽이는 가장 평범한 방법 외에도,
(2) 2층 이상의 높이에서 추락사시키기. 주인공은 이 경우 HP 하나만 잃지만, 악당은 의외로 즉사한다. 그 대신 악당은 1층 높이에서 떨어졌을 때 주인공처럼 무릎을 굽혀 엎드리지 않으며 바로 자세를 잡는다. 일당일단? 그리고 악당이 지금보다 아래 화면으로 떨어진 경우, 시체가 남지 않는다.
(3) 가시 꼬챙이가 있는 곳으로 떨어뜨리기. 한 층 높이에서만 떨어져도 주인공이든 악당이든 다 죽는다.
(4) 허리 자르는 쇠톱날.. 더 이상의 자세한 설명은 생략한다.

악당을 죽이고 나면 '빰 빠밤 빰' 하면서 승전 멜로디(?)가 흘러나온다. 칼로 찌르든, 떨어뜨리든 어떻게 죽이든지 말이다.
그런데... 페르시아의 왕자에서 악당을 (3)번, 즉 가시에다 밀어넣어 죽인 뒤에 승전 멜로디를 들은 적이 있으신 분 손..??
난 한 번도 없다. 20년 전부터 지금까지 이걸 대수롭지 않게 여기고 넘어가곤 했는데, 갑자기 문득 이상한 점이 느껴진다.

페르시아의 왕자 레벨에서 악당을 (3)번처럼 죽이는 건 레벨 2, 4, 8, 9(두 번), 11에서 총 6군데가 가능하다. 특히 마지막 레벨 11의 경우, 아예 왼쪽과 오른쪽에 모두 가시 트랩과 절벽이 존재하니 악당을 재미있게 요리하는 맛이 더욱 쏠쏠하다.

사용자 삽입 이미지사용자 삽입 이미지
사용자 삽입 이미지사용자 삽입 이미지
사용자 삽입 이미지사용자 삽입 이미지

악당을 정상적인 (1)번 방식으로 죽였을 때는 승전 멜로디가 무조건 나온다. (2)나 (4) 같은 트랩으로 죽였을 때는 아주 가끔 음악이 안 나오기도 했던 것 같다.
그 반면 (3)은... 지금까지 한 번도 나온 적이 없었다.
어떤 방식으로 죽든 악당의 HP가 0이 되어 전투가 끝나고 주인공이 칼을 집어넣을 때 승전 멜로디를 연주하면 될 텐데.. 로직을 상황별로 다 따로 처리했나? 그리고 저기서만 if문이 하나 실수로 빠진 건지? 진실은 그 당시 코딩을 했던 프로그래머만이 알 수 있을 것으로 보인다.

2.
자, 이제부터는 가시 말고 톱날 얘기가 줄곧 나올 것이다.
페르시아의 왕자의 일부 던전에는.. 톱날을 통과해 들어간 뒤에 곧바로 칼을 뽑고 악당과 싸워야 하는 곳이 있다. 레벨 4에서 처음으로 등장한다.
그런데 적과 싸우기 시작했을 때는 게임 진행이 조금 느려지고, 심지어 톱날의 톱질 주기도 약간 길어지는 것 같다.

이것은 시스템 성능 같은 다른 외부적인 문제일 뿐, 게임 메카닉 자체가 느려지는 건 아니다.
페르시아의 왕자는 참 좋은 게, ESC를 눌러서 게임을 일시 정지시키고 나서 계속 ESC를 누르면 게임을 한 프레임 단위로 천천히 진행시킬 수가 있다.
이걸로 측정을 해 보면, 톱날의 톱질 주기는 언제나 15프레임으로 동일하다. 전투 중일 때든, 평시든 말이다.

그리고 심지어 톱날이 여러 개 연달아 동작할 때도 동일하다.
각각의 톱날이 한 번씩 연달아 톱질한 뒤에 첫 톱날의 다음 주기가 시작되기 때문에 주기가 좀 길 것처럼 느껴지기 쉬운데, 그렇지 않다.

원작 게임에서야 톱날이 한 층에 가장 많이 등장하는 게 레벨 3의 대형 물약이 있는 방이다. 3개짜리가 최다이다.
유튜브 같은 데서 톱날이 5개가 넘게 있는 이상한 방을 가 보면, 모든 톱날들이 15프레임 안에 한 번씩 순회를 하는 게 불가능하다. 이런 데서는 뒤쪽의 톱날이 미처 톱질을 하기 전에 15프레임을 다 채운 앞쪽 톱날이 또 톱질을 시작한다.
게임 메카닉이 이러하다는 걸 알 수 있다.

3.
또한, 톱날은 주인공이 톱날과 같은 층에 진입한 경우 곧장 동작한다.
그런데 주인공이 그 층에서 다른 이유로 인해 죽어 버리면, 톱날은 일반적인 경우 동작을 멈춘다. 가령, 그 층에 있는 악당과의 전투에서 져서 죽거나, 칼을 뽑지 않은 상태에서 악당의 칼빵을 맞아 죽은 경우 말이다. 톱날이 있는 층에 주인공이 추락사를 했다면 톱날은 역시 더 동작하지 않는다.

하지만 주인공이든 악당이든 누군가가 그 톱날 자체에 찍혀 죽었다면 톱날은 계속 동작한다. 다시 말해 누군가를 한번 죽인 적이 있는 톱날은 그 층에서 주인공이 추락사하든 악당의 칼에 맞아 죽든, 주인공이 그 층에 어떤 형태로든 있다면 계속 동작한다.

사용자 삽입 이미지
내가 치트까지 써 가면서 다양한 상황에서 테스트를 해 보니 대략 그러하다. 알고리즘 차원에서 이런 미묘한 차이도 존재한다는 게 흥미롭지 않은가?

4.
그리고.. 주인공이 톱날이 존재하는 층에 있긴 한데, 추락하느라 잠시 지나는 형태라면 톱날은 어떻게 동작할까?
톱날은 이때도 반응한다. 레벨 9에서는 심지어는 주인공이 아니라 악당이 떨어지는데도 톱날이 한번 동작하니, 참 놀랍지 않을 수 없다. 아래 그림을 보시라.

사용자 삽입 이미지

그 반면, 주인공이라 해도 이렇게 지나갈 때는 톱날이 동작하지 않는다. megahit 치트를 써서 천천히 떨어지게 하는 낙하산 효과를 줬는데도 톱날이 동작하지 않는다.

사용자 삽입 이미지사용자 삽입 이미지
이런 걸 보면, 톱날의 동작 여부에는 우리가 흔히 생각하는 것보다 더 복잡한 로직이 들어간 건지도 모른다. 심지어 던전의 지형별로 톱날의 동작 여부를 제어하는 메타데이터가 수작업으로 들어간 건 아닌지?

5.
아까도 잠깐 얘기했던 레벨 3으로 돌아간다. 여기는 알다시피 최대 HP를 늘려 주는 대형 물약이 있지만, 그 길목을 저렇게 톱날이 무려 3개가 가로막고 있다.

사용자 삽입 이미지

페르시아의 왕자에서 레벨 3은 중간 waypoint가 존재하는 유일한 레벨이기도 하다. 죽으면 얄짤없이 처음부터 시작하는 게 아니라, 타임어택 절벽 관문은 통과한 뒤의 시점부터 시작한다는 뜻. 페르시아의 왕자 2야 각 레벨이 워낙 방대해진 관계로 waypoint가 존재하는 레벨이 더 생긴 편이지만, 1에서는 레벨 3이 유일했다.

레벨 12에도 그림자 인간과 합체하고 나서 Jafar를 만나기 직전 위치에 일종의 waypoint가 있긴 하지만, 이건 내부적으로는 완전 별도인 레벨 13으로 간주된다. 그렇기 때문에 레벨 3의 waypoint와는 약간 성격이 다르다.
관문을 통과하기 전에 대형 물약을 먹었다면, 그렇게 해서 늘어난 HP도 다음에 waypoint에서 게임을 다시 시작할 때 반영된다.

그런데, 여기에 약간의 버그 내지 exploit가 있다.
waypoint에서 게임을 다시 시작하면, 레벨 3의 모든 요소들이 원래대로 되돌아간다. 딱 하나, 그 타임어택 절벽 관문의 한쪽에서 우리가 도움닫기를 위해 밟아 떨어뜨려 없애던 발판만 계속 없는 채로 남아 있다.

그것만 빼고 나머지는 전부 원상복귀. 심지어 타임어택 절벽을 넘기 전에 먹었던 대형 물약도 다시 생긴다.
그렇기 때문에 다음 레벨로 넘어가는 관문을 열고 해골도 처지한 뒤, 다시 그 방으로 돌아와서 대형 물약을 먹으면.. 이론적으로 레벨 3에서 대형 물약을 두 번 먹어서 HP를 2개나 확장하는 게 가능해진다.

레벨 3 시작 → 대형 물약 → 타임어택 관문 통과 → 그 뒤 Ctrl+A 눌러서 waypoint 지점부터 게임 재시작. 예전에 대형 물약 먹은 게 반영됨 → 되돌아와서 대형 물약 또 먹음 → 클리어

물론 실제로 이렇게 하는 건 시간이 너무 많이 걸리는 노가다이기 때문에 현실성은 별로 없지만..
이건 아마 조던 메크너(오리지널 게임 설계자, Apple II용 개발자)와 랜스 그루디(도스용 게임 포팅 개발자)조차 그 당시 예상을 못 했던 꼼수일 것이다.
차라리 waypoint 이후에 도달하는 위치에다 대형 물약을 놔 뒀다면 이런 exploit가 틈탈 여지가 없었을 텐데.

자, 이런 글을 보니 나도 도스박스 깔아서 페르시아의 왕자를 실행해 보고 싶은 생각이 드시지는 않는가?

Posted by 사무엘

2014/06/29 08:21 2014/06/29 08:21
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/979

영화 <테이큰> 관련 소감

OCN인지 뭔지 영화만 하루 종일 상영해 주는 케이블 TV 채널을 보면.. 한때는 계속 유명 액션 영화만 틀어 주는 경우가 있었다. 그래서 본인은 원빈이 너무 멋있게 나온 <아저씨>, 또 B급 영화 오마주로 가득하면서 웬 인간 흉기 금발 백인 누님이 일본도 들고 싸우는 <킬 빌>을 TV를 통해 우연히 봤다. 그리고 이에 덧붙여 하나 더 본 게 있었는데 그게 바로 <테이큰>이었다.

사용자 삽입 이미지

본 소감은..
역시 흥행하는 영화는 뭐가 달라도 다르구나 싶었다. 리암 니슨 아저씨 너무 멋있다.
특히 딸 유괴범을 전기고문하면서 딸이 있는 곳을 알아내는 장면은 너무 통쾌한 권선징악 장면인지라 몇 번이고 다시 반복해서 봤다. 다같이 한번 살펴보도록 하자.

저 때 Wake up! I need you to be focused!로 시작하는 대사가 나온다.
다만, 인터넷에 굴러다니는 자막 파일은 그 문맥에서 대충 의미만 통하지 영어 원문의 정확한 의도를 다 전하고 있는 것 같지는 않다. 그 뜻은 대략 이렇다.

“(기절한 마르코를 의자에다 묶어 놓은 뒤) 어이, 일어나! 너를 심문을 좀 해야 하니 정신 바싹 차리고 있어라. 어금니 꽉 깨물어라, 자 간다~ (쇠꼬챙이를 양 허벅지에다 푹~ 박아 넣은 뒤) 자, 기절할 정도로 졸라 아프겠지만 고문은 아직 시작도 안 했다. 여전히 정신 괜찮지?”

이런 뉘앙스를 제한된 화면에다 문장으로 일일이 다 표현할 수가 없으니 Are you focused yet?을 “이제 정신이 좀 드나?”로 보통 번역하는 편이지만.. 원래 의미는 “아직 괜찮지?”에 더 가까운 게 아닌가 한다.

마르코는 처음에는 브라이언의 얼굴에다 침까지 뱉으면서 의기양양하게 반항하지만.. 전기로 10초간 지져지는 고문을 두 번 당하고 나니 기세가 완전히 꺾였다. 우리의 멘탈갑 브라이언은 표정 하나 안 변하고 태연~하게 이런 이 근안스러운 말을 해 댄다.

“이런 일은 말야, 원래는 외주를 주곤 했어. 그런데 문제는 외주 준 나라들이 대체로 못사는 개도국이어서 전력 공급이 불안했단 말이야..?? 스위치를 켰는데 전기가 안 들어와. 그러니 고문기술자들은 빡쳐서 사람 손톱을 뽑거나 생살에다 산성 용액을 부어 버리곤 했지. 일이 여러 모로 능률이 떨어지곤 했는데.. 여긴 전류가 아주 원활해서 좋아.”
“난 지금 바쁜 처지야. 마르코, 너 순순히 대답 안 하면 전기세 밀려서 단전될 때까지 스위치가 켜져 있을 거다.”

나중에 정보를 얻을 만치 다 얻은 브라이언이 다시 스위치를 켜러 가자 마르코는 완전 겁에 질려서 브라이언에게 눈물까지 글썽이면서 애원한다. “I don't know!! PLEASE..!! not that.. please ㅠ.ㅠ” 이 부분 연기를 처절하게 잘했다.
그래 봤자 브라이언은 “I believe you. But it's not gonna save you.”와 함께 스위치를 켜 놓고 나가 버린다. 마르코의 자백은 자기 수명을 불과 몇 분 남짓밖에 더 연장시키지 못했다.
허나, 부모가 수십 년간 피땀 흘리고 갖은 애정을 쏟아 키운 딸애를 창녀촌에다 팔아 버리고 돈은 자기가 챙긴 사악한 악당이라면.. 정말 저 정도 고문은 인과응보가 아닌가 싶다.

테이큰은 여타 액션 영화와는 달리 주인공이 친구의 마누라(악역이 아닌 여성!)까지 팔을 쏴 버리는 장면이 나오며,
또 최종 보스와 대면한 뒤에도 일말의 타협 없이 주인공이 그냥 곧바로 악당의 미간을 날려서 사건을 종결짓는다. 사건 전개가 참 자극적이고 짜릿하다.
사실, 브라이언이 친구를 다그칠 때도 “너 자꾸 고집 부리면서 협조 안 해 주면 니 애들은 고아가 될 거다. 아까는 생명에 지장이 없는 팔을 쐈지만 다음엔 급소를 쏠 거야?”라는 요지로 자막이 나왔는데, 이것도 정확하게는 단순히 급소가 아니라 '미간'이다. 영어 대사엔 eyes라는 단어가 들렸던 걸로 기억한다.

위의 장면들을 다 제치고 테이큰에서 리암 니슨이 남긴 제일 간지 넘치는 대사는, 역시 딸이 납치당한 직후 전화로 납치범에게 남긴 경고일 것이다. 딸이 외국에서 납치 당했지만 조금도 당황하지 않고 오히려 이 타이밍을 기다리기라도 한 듯이 납치범들을 상대로 나지막한 말투로 협박한다. 아아..;;

I don't know who you are. I don't know what you want. If you're looking for a ransom, I can tell you I don't have money (....)
If you let my daughter go now, that'll be the end of it. (...)
But if you don't, I will look for you. I will find you, and I will kill you.

..... good luck.

30초가 넘는 분량의 대사인데.. 난 다 외워 버렸다.

역시 사람은 자기 마음이 가는 곳에 역량이 발휘된다.
매주 교회에서 짤막한 성경 구절을 외운 건 길어야 그 날 저녁까지밖에 안 가고 세부적인 단어와 표현은 하루 이틀 정도 뒤면 까맣게 잊어버리는데.. 저건 그냥 머리에 확...

take는 성경에도 굉장히 자주 등장하는 동사인데, 저 영화를 보고 나니 take의 뜻조차도 좀 다시 생각하게 된다.
그래서 갑자기 똘끼를 발휘하여, 저 사건과 대사가 만약 흠정역 성경에 기록되었다면 어떨까 상상을 해 봤다. ㅋㅋㅋㅋ

... 그녀의 아버지가 이르되, 나는 네가 누구인지 알지 못하며 네 혼이 무엇을 원하는지(thy soul desireth) 알지 못하노라. 만약 네가 대속물(ransom)을 원한다면, 너는 확실히 알지니(of a surety) 내게는 돈이 없느니라. (...) 만약 네가 내 딸을 가게 하면 잘하는 것이려니와 만약 가게 하지 아니하면 내가 너를 쫓고 너를 찾아내어 너를 반드시 죽이리라, 하니라.
잠시 후에 그녀를 취한(took/taken) 자가 대답하여 이르되, 잘해 보라, 하니라.


그러고 나서 나중에 그런데 그것이 실제로 일어난지라 “너 나 기억 안 나? 우리 이틀 전에 서로 전화 통화 했었지? 내가 너 찾아낼 거라고 예고했잖아.” 이 말을 들었을 때 마르코는 얼마나 소스라치게 놀랐을까? 하지만 이미 때는 늦었다.. =_=;;;;

테이큰은 잔인한 폭력뿐만 아니라 창녀촌 배경도 있어서 그런지 국내에서는 생각보다 수위가 높은 19금 등급을 받고 개봉했다.
아무리 자기 딸을 구하려 한다지만 브라이언은 남의 나라에 들어가서 거의 30명 이상의 사람을 죽였다. 모 건설 현장을 완전히 작살을 냈으며 남의 자동차를 최소한 3대를 탈취하고, 고위 공직자의 부인을 총으로 쏴서 다치게 했다.

이 정도면.. 선한 의도라고 해도 브라이언은 법적으로 프랑스를 절대로 곱게 빠져나갈 수 없는 신세다. 그러나 영화에서는 그딴 시시콜콜한 디테일은 전혀 반영되지 않았다.
하긴, <킬 빌>에서도 키도 누님이 시퍼런 핫토리 한조 일본도를 비행기 기내에 버젓이 반입한 채 일본 본토로 날아가는 걸 보고, 본인은 피식 웃었다. 영화는 영화일 뿐.

<아저씨>에서는 그래도 최소한 차 태식이 체포되는 걸로 끝난다. 아무리 나쁜 조폭들을 죽인 거라지만, 일반인이 혼자서 다른 사람을 그렇게 많이 학살했다면, 현직 변호사의 자문에 따르면 아무리 명분을 참작하고 봐 준다 해도 무기징역감이라고 한다.;;;
하지만 태식의 경우 원래 특수부대 요원이었고, 아직 능력이 출중해 보이니 도로 국가를 위해 현업 복직하는 것을 조건으로 검찰에서 기소조차 하지 않고 학살극을 유야무야하는 쪽으로 갈 것이다. 조폭들이 죽은 건 자기들이 팀킬 벌인 거라고 적당히 위장하고 말이다.

말초신경을 자극하는 폭력 액션 영화에 너무 심취하는 건 사람의 정신 건강에 그다지 좋다고 볼 수는 없다.
그러나 국가가 흉악 범죄자에게 권선징악을 속 시원하게 집행을 안 하고 되도 않은 인권 핑계로 직무유기를 저지르니, 사람들이 현실적으로 영화에서 대리만족을 얻게 된 것도 부정할 수 없을 것이다.
괜히 종교색 표방하면서 교묘하게 성경이나 하나님에 대해 왜곡된 이미지를 전달하는 매체보다는, 차라리 종교색 따윈 싹 잊고 말초신경만 자극하는 게 '덜' 해로운 건지도 모르고 말이다. 성경 용어로 설명하자면 전자는 마귀적(반성경적)이며 후자는 육신적(비성경적)이라고 표현할 수 있겠다.

Posted by 사무엘

2014/06/26 19:29 2014/06/26 19:29
, ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/978

1.
내 자신의 마음과 행동에 대해서 스스로 판단할 때는 절대로 남 따위와 비교하지 말고 성경과 비교하고 하나님의 법과 '절대적인 잣대로' 비교한다.
그 반면, 위의 권위와 위정자에 대해서는 “이게 그나마 불신자가 불신자를 통제하고 죄의 결과를 제어하려는 최선의 방법이구나. 비록 멍청하거나 사악하거나 혹은 둘 다일 때도 왕왕 있지만, 이거라도 없으면 세상은 더 망가질 수밖에 없으니, 내 신앙을 가로막는 것만 아니면 최대한 긍정적으로 보고 순종해야지”라는 '상대적인 잣대'로 접근하면 된다.

이 생각이 딱 정립돼 있으면 정신 건강에 여러 모로 좋다.
큰 절대악에 대해서는 절대 침묵하고서 불가피한 필요악의 작은 폐해만 자꾸 부각시키면서 없애고 뒤집어엎자고 드는 선동질, 반골 기질, 쓸데없는 세상 비관과 피해의식, 하나님보다 더 자비로운 인권 드립, 그리고 인간의 죄성상 절대로 가능하지 않은 사회 제도가 존재 가능하다고 속삭이는 속임수 등등에 넘어갈 일이 없게 되기 때문이다. 저건 전부 성경과 도저히 어울릴 수 없는 잘못된 사고방식이다. 내가 가끔 정치색 띤 글을 쓰는 건(특히 종북들 까는) 전부 이 카테고리에 해당하는 아이템들로 한정해서이다.

2.
신약 성경에 나온 긍정적인 얘기들, 대표적으로 빌 4:13 (나를 강하게 하는 그리스도), 롬 8:28 (모든 것이 합력하여 선을 이룸) 같은 것들은...
쉽게 말해 너도 성령의 능력을 힘입어 환경 여건에 구애받지 않고 예수님을 닮고 그분의 열매를 맺는 게 '이론적으로' 가능하다는 얘기다. 세상적으로는 오히려 바보 되고 손해 보더라도 말이다. 빌 4장 전후 문맥을 보면 아주 쉽게 유추 가능한 얘기임. 무슨 예수 버프를 받아서 세상적으로 성공하고 내 야망을 다 이룰 수 있다는 얘기가 절~대로 아니다!

그리고 롬 8:28도 당신이 육신적으로 절대로 원하지 않는 중간 과정과 결말을 다 포함할 수도 있는 얘기다. 신약 성경은 단순히 “차카게 살자” 수준을 넘어서 흔한 통념보다 굉장히 영적이고 고차원적인 주제를 다루고 있는 책이다. “하나님의 왕국과 그분의 의”가 무엇인지, 그런 문맥에 익숙해지는 훈련을 요한복음을 읽을 때쯤부터 미리 해야 한다.
그래야만 우리도 “제발 복 좀 주시옵소서”에 앞서 “우리가 이미 받은 복이 얼마나 큰지부터 알 수 있는 안목을 주시옵소서” 기도부터 먼저 한 에베소서 1장의 바울의 심정을 이해하게 된다.
신약 성경을 제대로 읽으면 이상한 은사주의 기복 신앙 같은 데에 빠질래야 빠질 수가 없다.

3.
신구약 성경 전체의 핵심 주제는 인간의 구원이나 크리스천의 양육 같은 게 아니다. 겨우 그게 전부라고 생각하기에는 성경엔 나머지 잉여스러운 내용이 분량이 너무 많고 그쪽 묘사들이 “쓸데없이 고퀄”이다.
성경에는 예수님의 초림보다 재림 예언이 더 많고, 이뤄진 예언보다 아직 안 이뤄진 예언이 더 많이 적혀 있다. 특히 이스라엘, 유대인의 문자적인 회복을 거듭해서 강조한다. 이 이스라엘과 유대인이 문자적인 이스라엘과 유대인이 아니라고 가르치거나 교회가 유대인을 대체했다거나 영적 유대인 드립 친다거나, “예수님을 죽인 나쁜 민족” 운운하면서 반유대주의를 조장한다거나, 14만 4천 명이 자기 교단이라고 가르치는 것들은 전부 성경을 잘못 가르치는 이단 교리다. 그런 데서는 당장 떠나고 나오시라.

성경 내용을 영적으로 적용하더라도, 누구에게나 동일하게 읽히는 문자적 1차 의미가 무엇인지 알기는 하고서 “그 다음에” 내 개인에게 유익이 될 수 있는 영적 교훈을 찾아야 한다. 도대체 어느 문맥에서는 “눈에는 눈, 이에는 이”이고 어디서 “원수를 사랑하고 왼뺨 맞으면 오른뺨도 대라”가 적용되는지를 제대로 분간할 줄만 알아도 최하 95%가 넘는 이단에는 안 빠질 수 있으며, 성경 읽는 기본 자세의 반은 마스터한 게 아닐까 싶다.

4.
세상에 복음과 구원 말고 공짜란 없다. 어디 하나가 공짜라면 다른 한쪽에서는 반드시 바가지나 착취나 희생이 존재한다. 아니, 구원이라는 공짜마저도 예수님의 보혈 덕분에 가능한 것이니 거시적으로는 공짜가 아닌 셈이다.
여기에 대해서는 본인이 예전에 경제관 쪽으로 글을 쓴 적이 있고 성경 교리 쪽으로도 글을 길게 쓴 적이 있다. 중요한 주제이니 관련 글을 반드시 참고하시라.

5.
크리스천의 윤리관은 그야말로 완전 보수 수구 꼴통급이다. 여기에 대해서는 역시 예전 글을 참고하시라.
그리고 역시 위의 예전 글에서 언급한 내용이다만, 크리스천은 이 세상에서 사는 게 끝이 아니라는 걸 알며, 죽음에 대한 두려움, 죽은 자에 대한 각종 이상한 미신(귀신 따위), 필요 이상의 신세 한탄, 트라우마, '천추의 한' 같은 게 (일단은) 없다. 이것도 사람의 멘탈을 굉장히 건전하게 만드는 데 기여하는 가치관이다.

6.
끝으로..
요즘 같은 세상에서 성경대로 살기란 도저히 불가능하다는 생각이 드는가? 신이 대체 존재하기는 하는지 의구심이 드는가?
예수 믿느라 나 혼자만 잔뜩 손해 보고 생존 경쟁에서 뒤쳐지고 부당한 일, 너무 억울한 일을 당한다는 생각이 드는가? 도대체 이것도 하지 말고 저것도 하지 말고 어떻게 살라는 건지 감이 안 오는가?
내가 인간적인 논리를 동원해서 그 질문에 대한 납득할 만한 답을 줄 수는 없다. 크리스천이라고 해서 마냥 동네북, 호구처럼 로봇처럼 살라는 말도 당연히 절대 아니다. 다만 난 이런 말은 해 줄 수 있다.

먼저, 바로 그런 이유 때문에 하나님은 인간에게 정말로 필요한 구원 조건, 하나님을 찾는 통로로.. 인간의 다른 그 어떤 스펙이나 외모, 능력도 모조리 제끼고.. 제일 하찮고 나약하고 바보 같아 보이는 '믿음'이라는 것만을 남겨 놓았다는 것이다. 이걸 기회로 삼아야 한다.

왜 하나님이 세상을 그런 원리로 만들어 놓았는지 제대로 이해는 못 하겠지만, 그렇기 때문에 하나님은 모든 사람들에게 정말로 공평해야 하는 것은 진짜 공평하게 돌아가게 해 놓으셨다.
그게 아니라면, 당신보다 더 잘났고 더 똑똑하고 더 부유한 사람들이 진작에 하나님을 당신보다 먼저 만났을 것이며 게임 다 끝났을 것이다. 그리고 하나님을 만나는 데 필요한 그 수단을 인간에게 너무 불공평하게 배분해 놓으신 하나님이 불공평하고 잘못된 꼴이 된다. 다른 능력자들이 다 안 믿을 때 당신이 믿어야 인생의 최후의 승리자가 될 수 있다.

그리고 부당한 일, 억울한 일이라고?
이 세상은 하나님께서 악한 카인을 벌을 내려 일찌감치 죽여 버린 게 아니라 반대로 의인 아벨이 카인에게 살해당하는 걸 허락하실 때부터.. 애초에 그 시절부터 불공평하기 시작했다. 저건 전혀 새삼스러운 현상이 아니다.
예수님의 죽으심 사건도 얼마나 추악하고 황당무계한 비리와 부조리 속에서 벌어진 일이었는지 역시 설명이 필요하지 않을 것이다. 하나님조차 그 악한 시스템을 한시적으로나마 인정하고 그 시스템을 역이용하여 자기 구원의 사역을 수행하셨으니 우리 역시 너무 피해의식 갖지 말자.

또한 우리의 모든 마음속 생각과 일거수일투족이 다 훗날 심판석 앞에서 회계보고가 될 텐데, 정산되지 않고 숨겨진 죄가 드러나서 하나님 앞에서 쪽팔림을 당하는 것만큼이나.. 그렇게 의로운 행실 때문에 손해 보고 부당함과 고난을 당한 것도 “똑같은 맥락으로” 그때 다 드러나서 보상받는 날이 온다는 걸 생각해 보자. 그거.. 영구적인 손해가 절대 아니다.

성경이 말하는 믿음이란 건 아Q 같은 근자감 정신승리법이 아니다. 영적 배후가 걸린 각종 문제들은.. 그 문제 자체가 물리적으로 제거됨으로써 해결되기보다는
내가 문제를 바라보는 발상을 바꾸고 안목을 바꿔서 성경이 약속한 모든 이해를 초월하는 평강(빌 4:7)을 얻음으로써 해결되는 경우가 많다. 그래서 욥기만 봐도 하나님은 욥의 고난과 직접적인 관련이 있는 말은 단 한 마디도 안 하셨지만 욥이 알아서 데꿀멍하게 된 것이다.

또한 악한 마귀의 통치하에 있는 현 세상은.. 사람이 그 믿음을 행사를 못 하게 시스템을 착착 만들어 놨다는 점을 잊지 말아야 한다.
성령 충만한 크리스천하고는 아무 상관 없는 이상한 사람들, 잘못 믿고 성경을 잘못 적용하는 사람들의 바보짓, 병크를 잔뜩 부각시키면서 이래서 종교에는 너무 빠져들어서는 안 된다는 식으로 영적으로 연약한 사람들의 믿음을 파괴한다. 하나님의 뜻을 오· 남용하는 것, 교회와 유대인을 구분 못 하는 것이 대표적인 예.
이러니 바른 성경 원천을 토대로 바른 믿음을 보기가 갈수록 어려워지는 게 오늘날의 모습이다.

“저런 사람이 믿는 예수라면 나도 한번 믿어 보고 싶다” 정도의 엄청난 선한 간증이 있는 크리스천이 세상에 과연 얼마나 있을까? 그런 평판은 나조차도 감당 못 하며 기대 안 한다.
그러나 그렇다고 해서 자괴감 가질 필요도 없고, 내가 예수님을 위해서 내 힘으로 이를 악물고 뭔가 엄청난 극기과 선행과 고행을 해야 한다는 식으로 생각할 필요는 더욱 없다.

난 딱 하나가 목표이다. 오로지 교리만을 있는 그대로 정확하게 전해서, 누가 그걸 안 믿고 반대하더라도 뭐가 기독교인지 정확하게 알긴 하고서 제대로 반대하게 만드는 것이다. 그들에게는 안 믿을 권리는 있어도, 기독교가 아닌 걸 기독교라고 주장할 권리는 없기 때문이다. 굳이 긍정적인 변화가 아니더라도 부정적인 편견을 막는 것도 인정받는 것 맞다.

나일롱 신자인 건 하나님 앞에서 겸손도 아니고 자랑도 아니다. 교회사에 등장하는 순교자나 각종 '성인'(?)들의 행적이 자기와는 완전 별개 딴판이라고 생각하는 것은 매우 잘못된 생각이다. 성경이 압수되고 성도들이 화형을 당하던 시대에 치러지던 영적 전쟁이 있고, 성경이라 불리는 물건이 넘쳐나지만 그게 죄다 변개되는 오늘날 같은 시대에 치러지는 영적 전쟁도 따로 있다. 난 그걸 추구하며 지낸다.

Posted by 사무엘

2014/06/18 08:33 2014/06/18 08:33
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/975

하루는 본인은 회사 업무를 위해 인터넷에 굴러다니는 어느 암호화 알고리즘 소스를 프로젝트에다 붙여 쓴 적이 있었다.
그런데 곧장 문제가 발생했다. 본인이 맡은 부분은 Windows용 클라이언트인데, 같은 소스를 사용하는 다른 플랫폼 클라이언트 내지 서버와 교신이 제대로 되지 않고 있었다.

결국은 문제의 코드를 별도의 콘솔 프로그램 프로젝트로 떼어서 따로 돌려 보니, 문제의 원인은 그 암호화 알고리즘에 있음이 밝혀졌다. 같은 소스를 빌드해서 돌렸는데 결과가 서로 차이가 나는 것이었다.
게다가 Visual C++로 빌드하는 같은 Windows용 프로그램도, 알고 보니 debug 빌드는 결과가 옳게 나오는데 release 빌드만이 문제가 있었다!

debug와 release가 서로 다르게 동작하는 프로그램은 십중팔구가 멀티스레드 race condition 아니면 단순 초기화되지 않은 변수 때문이다. 물론 이 코드는 스레드를 따로 만들지는 않으니 의심 부분은 응당 후자. 이거 또 남이 짜 놓은 복잡한 코드에서 꼭꼭 짱박혀 있는 버그 찾느라 무진장 고생하겠다는 생각과 함께 몇 시간 동안 디버깅을 진행했다.

release 모드로 빌드된 프로그램은 함수 인라이닝과 각종 최적화 때문에 debug 빌드처럼 한 라인씩 엄밀하게 step in이 되지 않으며 변수값 조회도 안 되는 경우가 종종 있다. 그러니 도대체 언제부터 두 빌드의 변수값이 달라지는지 printf 신공을 펼치면서 꽤 어렵게 문제 원인을 추적해야 했다.

문제의 범위는 많이 좁혀졌다. stack이나 heap 메모리를 초기화하지 않고 쓴 경우는 눈을 씻고 찾아도 없었다. 마치 난수 씨앗처럼 초기의 동일한 input으로부터 일련의 output들이 계산을 통해 파생되는데, 언제부턴가 두 빌드가 생성해 내는 변수값이 미묘하게 서로 달라지는 게 보였다. 저 동일한 input 말고 계산에 영향을 끼치는 요소는 정말 없는데? 왜 값이 달라지지..?

그리고 결국은 설마 하던 녀석이 사람을 잡았다는 걸 알게 됐다. 문제의 함수는 바로.. 이것이었다!

unsigned long Rol(unsigned long x, long y)
{
    if (y % 32 == 0) {return x;}
    else {return ((x << y)^(x >> -y));}
}

저 간단한 함수의 실행 결과가 release 빌드와 debug 빌드가 서로 달랐다. 비주얼 C++ 2012, 2010, 2003 전부 공통으로.
암호화 알고리즘에서 절대 빠지지 않는 그 이름도 유명한 비트 회전(bit rotation)을 구현한 함수인데..
비트를 음수 shift하는 연산은 좀 생소해 보였다.

본인은 15년 가까이 C/C++ 프로그래밍을 해 오면서 지금까지 막연히 A<<-B = A>>B, A>>-B = A<<B이지 않으려나 생각해 왔다.
그런데 실상은 전혀 그렇지 않았다.
컴퓨터의 구조적인 특성상 나눗셈에서 피연산자의 부호에 음수가 섞이면 몫과 나머지의 부호가 수학에서 생각하는 직관적인 형태로 구해지지 않는다는 건 어렴풋이 알고 있었다만, 비트 shift에도 그런 특성이 있구나.

음수 shift의 결과는 언어 스펙 차원에서 undefined인 모양이다. 진짜 말 그대로 A=A++처럼 '그때 그때 달라요'인 듯.
중의적인 코드를 컴파일러마다 제멋대로 번역하는 것 자체를 모조리 막을 수는 없겠지만, 그건 최소한 '이식성'에 문제가 생길 수 있다고 경고라도 띄워야 하지 않나 싶다.

실제로 위의 함수를 실행하면

Rol(0xBE9F8300, 1);
Rol(0xEC6BFC33, 1);
Rol(0xFC58371A, 1);

의 함수값은 release 빌드에서는 각각 0x7D3F0600, 0xD8D7F866, 0xF8B06E34이 나온다.
그러나 debug 빌드에서는 0x7D3F0601, 0xD8D7F867, 0xF8B06E35가 나오며, 이게 맞는 값이다. release는 무슨 이유에서인지 최하 자리 1비트를 누락하고 있었던 것이다. 그러니 이후의 암호화 결과가 몽땅 틀어지는 건 당연지사.
설상가상으로 xcode에서는 더 이상한 결과가 나왔던 걸로 기억한다.

유명 암호화 라이브러리가 왜 저렇게 이식성 없는 연산을 썼는지 난 잘 모르겠다. 음수 shift의 결과가 어떻게 나올 것을 기대한 건지?
저 문제를 우회하느라 지금까지 머리로만 알고만 있었지 실무에서 쓸 일이 전혀 없으리라 생각했던 테크닉을 쓰게 됐다.
소스 코드의 특정 구간에 한하여 최적화를 잠시 끄는 #pragma optimize("", off) 되시겠다.

bit rotation은 bit shift에다가 한쪽 끝에 있는 비트들을 따로 반대편 끝에다 shift시켜서 얹어 준다는 차이만이 있을 뿐이다. 32비트 부호 없는 정수 기준으로, 작은 자리수가 큰 자리로 이동하는 왼쪽(<<) rotation을 나보고 구현하라면 이렇게 짜겠다.

UINT Rol2(UINT x, int y)
{
    return (x<<y)|(x>>(32-y));
}

32라는 숫자가 보기 싫으면 sizeof 등을 써서 다른 방식으로 바꾸면 되고.
그리고 이렇게만 짜도 컴파일러는 이 연산 전체의 의미를 알아보고 당연히 rol이라는 '비트 왼쪽 회전'이라는 '한 인스트럭션'으로 최적화해서 번역해 준다. bit shift인 shl, shr만큼이나 rotation도 굉장히 기계 친화적인 동작이며, 전용 명령이 있는 것이다. 하지만 정작 저 공개 라이브러리 함수는 Visual C++ 컴파일러가 rol이라고 최적화하지 않는다.

아마 -n shift는.. 전체 비트수에 대한 보수(32-n)만치 shift하는 것과 같다고 전제를 한 듯하다.
그리고 or 대신 xor을 쓴 것은 그게 컴퓨터 구조 차원에서 기계어 코드 길이가 더 짧거나 속도가 조금이라도 더 빨라서 그런 듯하다. 필요하다면 x=0조차도 x^=x로 표현하는 게 컴퓨터 세계이니 말이다.

결국은 음수 처리까지 정확하게 해서 shift든 rotation이든 -n만치 하는 건 반대편으로 n만치 하는 것과 같은 게 보장되는 함수를 만들려면..
if문을 써서 처리를 완전히 따로 하고 <<, >> 자체에는 어떤 경우든 음수 shift가 존재하지 않게 하는 게 이식성 면에서 가장 좋은 해결책으로 보인다. 흥미진진한 경험을 한 날이었다.

Posted by 사무엘

2014/06/15 08:36 2014/06/15 08:36
, ,
Response
No Trackback , 6 Comments
RSS :
http://moogi.new21.org/tc/rss/response/974

오래 전, 본인은 PE 방식이라고 불리는 32비트 Windows 실행 파일의 내부 구조에 대해 처음 알아 가던 시절에 굉장히 신기해한 사실이 하나 있었다. 그건 바로 파일 내부에 자신이 호출하는 API 함수의 이름이 다 나와 있다는 점이었다. 그러면 이 프로그램이 대충 무슨 기능을 활용하며 만들어졌는지도 얼추 분석이 가능해질 텐데? 16비트 바이너리에는 이런 정보가 존재한 적이 없었다. (오히려 EXE가 윈도우 프로시저 같은 콜백 함수 이름을 노출하고 있었음)

static library가 그러한 것처럼 DLL도 프로그래머가 작성한 클래스/함수가 이름이 그대로 외부로 노출된다. 그 이름을 GetProcAddress에다 전달하면 이름에 해당하는 함수 주소를 얻을 수 있다.

그러나 DLL이 제공하는 심벌들은 이름뿐만 아니라 ordinal이라고 불리는 번호도 제각각 다르게 부여받는다. 그렇기 때문에 ordinal로 주소를 얻는 것 역시 가능하다.
이 ordinal은 index나 number이 아니라 ID에 가까운 개념이다. 반드시 0부터 N까지 조밀하게 분포해 있어야 할 필요가 없으며 1000부터 시작해도 되고 중간에 빈 번호가 있어도 괜찮다.

단, 범위는 16비트로 한정이다. GetProcAddress 함수는 인자의 정수값이 16비트보다 크면 포인터로 간주하여 문자열 검색을 하며, 그보다 작은 값이면 ordinal로 간주하여 숫자 검색을 하는 방식으로 동작한다.
다시 말해 Windows의 DLL은 구조적으로 65536개 이상의 심벌을 export할 수는 없다. 물론 그렇다 해도 이것은 현실적으로 아무런 한계가 없는 것이나 마찬가지다.

16비트 시절에는 DLL의 심벌 탐색이 이름이 아닌 오로지 ordinal 방식만 지원되었던 모양이다. (그럼 GetProcAddress 함수도 인자가 PCSTR이 아니라 그냥 UINT였나?)
문자열을 비교하는 것보다는 숫자를 비교하는 게 속도도 더 빠르고 공간도 더 적게 차지하니 좋다. 그러나 ordinal 방식은 두 가지 단점이 있는데, 먼저 보안이 좀 더 안 좋으며, 그리고 ordinal 관리가 매우 까다롭다는 점이다.

보안 이슈는 쉽게 비유하자면 이렇다.
GetProcAddress("My_unique_function_name")은 내가 직접 만들지 않은 DLL 에서는 성공할 확률이 거의 없다. 그 반면, GetProcAddress((PCSTR)5)는 함수깨나 있다 싶은 아무 어중이떠중이 DLL에서도 어지간해서는 성공하게 된다.

즉, 엉뚱한 DLL을 잘못 불러왔을 때, 이후 동작이 안전하고 깔끔하게 실패하는 게 아니라 그 상황을 사전 감지를 못 하고 나중에 crash로 도질 가능성이 높다는 뜻이다.
물론, 여기서 보안이라는 건 프로그램 실행과 관련된 보안이다. ReadFile, CreateWindow 이라는 함수 이름 대신 #35, #107 식의 암호 같은 ordinal은 프로그램의 역공학을 어렵게 하는 보안(?)은 더 뛰어날 수도 있으니 말이다.

ordinal 관리 문제는 생각보다 더 까다로운 문제이다.
어떤 DLL이 개발이 한창 진행 중이어서 수시로 함수가 추가되거나 삭제된다고 생각해 보자. 그렇더라도 한번 번호가 부여된 함수는 번호가 절대 고정불변이어야만 그 DLL을 사용하는 프로그램과의 하위 호환성이 보장될 수 있다.

같은 함수라도 DLL의 다음 버전에서 ordinal이 달라져 버리면 기존 프로그램은 그 DLL을 사용할 수 없게 된다. 그런데 수백, 수천 개의 ordinal간에 결번이 생기고 영역이 추가 할당되는 것, 과연 번호 관리가 그렇게 호락호락 수월하게 가능할까?

이런 이유로 인해 32비트 이래로 DLL 심벌은 ordinal이 아닌 문자열로 import/export하는 게 관행이 되었다. 16비트 시절에는 DLL을 하나 만들려면 DEF 파일을 무조건 반드시 만들어야 했고 export하는 심벌에 대한 ordinal을 수동으로 기입해야 했다.
그러나 32비트부터는 export하는 심벌만 쭉 기입해 주면, ordinal은 그냥 이름들의 ABC순으로 0부터 N까지 자동으로 생성된다. 별로 중요하지 않은 정보가 됐기 때문이다.

그러나 오늘날에도 ordinal이 전혀 불필요하고 쓸데없느냐 하면 그렇지는 않다.
딱히 컴포넌트화를 지향하지 않고 내가 만드는 프로그램에서나 내부적으로 몰래 쓰는 소형 private DLL이라면, export하는 함수의 이름이 전혀 중요하지 않을 테니 그냥 이름을 노출할 필요도 없이 ordinal 직통을 쓰면 된다. 하는 일이 붙박이로 정해져 있고 앞으로 프로토타입이 바뀔 일이 절대로 없는 물건이라면 금상첨화. 훅 프로시저 DLL 같은 게 좋은 예 되겠다.

혹은, 심벌 개수가 수천~수만 개로 너무 많은 대형 DLL의 경우, 로딩 시간을 조금이라도 단축하기 위해서 의도적으로 이름 대신 ordinal 기반 로딩 방식을 고집하기도 한다.
당장 MFC 라이브러리, 그리고 MS Office가 내부적으로 사용하는 공용 라이브러리인 mso.dll도 전부 ordinal 기반이다. MFC를 DLL 링크한 프로그램이라고 해서 export 섹션에 CWnd, CWinApp 이런 클래스 심벌들이 주룩 노출돼 있는 거 아니다.

심벌을 이름이 아닌 ordinal로 식별하게 DLL과 import library를 만들려면 빌드 시에 DEF 파일을 만들어서 심벌에 대한 특성과 ordinal 번호를 수동으로 지정해 줘야 한다.
그런데 C가 아닌 C++ 스타일의 클래스나 함수를 ordinal로 지정하는 법은 잘 모르겠다. 비주얼 C++ 스타일로 복잡하게 decorate된 명칭들을 일일이 다 열거하면서 @번호 NONAME 속성을 다 줬으려나? 그것도 보통일이 아닐 텐데.

Posted by 사무엘

2014/06/12 08:33 2014/06/12 08:33
, ,
Response
No Trackback , 3 Comments
RSS :
http://moogi.new21.org/tc/rss/response/973

다윗, 미갈 이야기

1. 다윗의 조약돌

성경에 나오는 다윗과 골리앗의 싸움 장면을 모르시는 분은 없을 것이다.
그런데 하나 같이 좀 생각해 보자. 다윗은 골리앗과 싸우러 나갈 때 왜 조약돌을 5개씩이나 챙겨 갔을까? (삼상 17:40)

“발사한 돌이 빗나가는 경우 / 골리앗이 한 발 만에 안 죽을 경우에 대비해서” 같은 답변은 말이 되지 않는다는 걸 금방 알 수 있다.
필살의 일격 단 한 발로 미간을 명중시켜서 인간 흉기 골리앗을 즉사 내지 최소한 기절이라도 시키지 않으면, 다윗은 곧바로 반격을 당해서 다음 돌은 쏴 보지도 못하고 죽는다. 이 조약돌은 FPS 용어로 치면 일종의 레일건인 것이다. 골리앗은 BFG로 무장해 있었고 말이다. 그러니 한 발 이후로는 의미가 없다.
 
역사적으로 볼 때, 살아서 돌아오지 못할 비장한 각오를 단단히 한 사람들은... 거사를 치르기 전에 일부러 자기에게 주어진 리소스를 딱 자기 여건에 맞춰 제약하는 퍼포먼스를 행하곤 했다. 일종의 배수진이랄까?
 
안 이숙 여사는 왕복이 아닌 편도 배삯만 치르고 일본에 갔으며,
윤 봉길 의사는 폭탄을 던지러 가기 전에 김 구와 손목시계를 교환하여 자기가 더 저렴한 것을 챙겼다.
옛날 백제의 계백 장군은 마지막 전투를 치르기 전에 자기 처자식부터 미리 죽였다..;;
 
다윗도 만약 그런 식으로 비장하게 행동했다면 필생필사의 각오로 돌을 달랑 하나만 챙겨 가는 게 자연스러웠을 것이다.

그러나 그가 그런 스타일로 행동하지 않은 이유는 간단하다. 그는 하나님이 지켜 주시는데 자기는 죽을 일이 절대로 없으며, 골리앗을 무찌르고 멀쩡히 돌아온다고 확신했기 때문이다. 일이 틀어질 가능성 따윈 전혀 고려조차 하지 않은 것이다. 남들이 보기엔 그건 영락없이 '근자감'처럼 보였겠지만 말이다. 그래서 그는 가진 자의 여유마냥 별 생각 없이 평상시처럼 여러 스페어 조약돌을 챙겼다.

아니, 어쩌면 그는 골리앗 정도를 초월하여 아예 이렇게 생각했을 수도 있다.
당장 현실의 목표물인 골리앗을 원 샷 원 킬 하는 건 너무 당연한 소리이고, 혹시 이 돌발상황 결과에 불복하여 예정에 없던 다른 거인들이 또 튀어나와서 시비를 걸면, 그놈들까지 이 조약돌로 잡아야겠다는 준비까지 한 건지도 모른다!
실제로 성경을 보면 거인이 골리앗만 있었던 건 아니며 당장 골리앗에게도 혈육상의 친동생이 있었다고 나오니까 말이다.
 
이 PvP에서 다윗은 골리앗을 PK하고, 골리앗이 갖고 있던 커다란 검을 득템했다. 참고로 사무엘기상 17장을 읽어 보면, 성경은 골리앗을 골리앗이라고 부르는 걸 극도로 기피하면서 의도적으로 '그 블레셋 사람'이라고 에둘러 가리키는 걸 볼 수 있다.

2. 사울의 둘째 딸 미갈

성경에서 사울 왕의 딸이 본격적으로 등장하는 건 다윗이 골리앗을 죽여서 완전 나라를 구한 영웅이 된 뒤부터이다. 영웅이 된 건 좋은데 다윗이 너무 유명해지고 왕보다도 인기가 올라가자, 그는 왕의 눈 밖에 나 버렸다.

이거 뭐 누명을 씌워 죽일 수도 없고.. 왕은 꼼수 차원에서 다윗을 전쟁터에서 죽게 하려고 높은 군사 직위를 주었으며, 자기 딸을 다윗에게 주어 결혼시켰다. 사실, 왕의 사위로 만들어 주겠다는 건 삼상 17:25에서 이미 약속된 사항이기도 했고 말이다.

그런데, 다윗은 자기 같은 가난하고 천한 사람이 감히 왕의 딸과 결혼할 수는 없다고 제안을 고사했다. 이에 왕은 다윗을 또 전쟁터에서 죽게 할 명목으로, 아무 지참금 따위 안 받을 테니 다만 민족의 원수 블레셋 사람 100명을 죽여서 놈들 포피만 가져오면 둘째딸 미갈을 아내로 주겠다고 제안했다.

그러자 다윗은.. 미갈이 마음에 들었는지, 나가서 블레셋 사람 200명의 포피를 갖고 멀쩡히 돌아왔다. 그래서 결혼에 골인했다.
생각을 해 봐. 사랑하는 마누라를 얻으려고 목숨 걸고 전쟁터에서 사람 수백 명을 죽이는 게 어디 쉬운 일이겠는가.

그러나 이렇게 맺어진 결혼 생활은 그리 단란하지 못했으며 오래 못 갔다.

미갈은 거짓말까지 해 가며 다윗의 도피를 도와 줘야 했으며, 별거 모드에 빠졌던 그녀는 훗날 아버지의 명에 의해 '발디/발디엘'라는 다른 남자에게로 강제 재혼을 당했다. (삼상 25:44) 그 동안 다윗은 타지에서 또 아비가일, 아히노암이라는 아내를 두 명이나 추가했고 말이다.

허나 여기에도 반전이 있었으니...
나중에 다윗은 긴 도피 생활을 마치고 왕이 된 후, 발디에게서 미갈을 도로 뺏어 와 버렸다! (삼하 3:14-16)

아무 영문도 모른 채 하루아침에 마누라를.. 그것도 자기 나라 왕에게 빼앗긴 발디는 엉엉 울면서 미갈을 뒤따라 갔는데.. 군대 대장 아브넬의 “그만 꺼져”(성경에는 그냥 Go return이지만..ㅎㅎ) 한 마디에 “넹.. ㅠ.ㅠ” 깨갱 하고 버로우 타 버린 완전 안습한 남자로 성경에 나온다. 성경에서 처지가 제일 처량한 남자가 아닐까 싶다.

이렇게 다윗과 미갈은 재회를 하였으나, 궁극적인 결말은 또 다시 불미스러웠다.
사사 시절 이래로 방치되어 있던 언약궤가 돌아오던 날, 다윗은 왕의 체면도 다 버리고 너무 즐거워서 백성들과 덩실덩실 춤추고 즐겼는데...

미갈은 그때 무슨 생각을 했는지 남편에게 “품위라고는 안드로메다로 보내 버리면서 당신 참 가관이더군요”라는 요지로 비아냥거리면서 굉장한 악담을 퍼부었다.

다윗도 이것만은 영적인 문제인지라 그냥 넘길 수 없었고, 아내에게 굉장히 실망을 한 듯하다. “나를 왕으로 세우신 하나님 앞에서 나는 지금보다 더 어리광 부리고 기꺼이 더 망가질 수도 있소. (그리고 그러더라도 나는 당신이 언급한 그런 천한 여자들보다는 하나님 앞에서 더 대접을 받을 테니 걱정 마쇼.)”

그 뒤로 미갈은 자녀 없이 쓸쓸한 말로를 보내게 되었다고 한다. (삼하 6:23) 그 시절에 유부녀가 자기 자녀가 없는 것은 거의 죄악에 가까운 굉장한 치욕이었다는 점을 생각하자.

이것이 단순히 금슬에 금이 간 것인지, 아니면 하나님께서 생리학적 불임을 만들어 버리신 것인지는 확실치 않다.그러나 인간의 출산을 굉장히 주관적으로 좌지우지하는 성경의 전반적인 심상으로부터 유추했을 때는, 후자일 가능성이 높다.

그리고 이것이 성경에 등장하는 미갈의 마지막 장면이다. 처음엔 다윗이 미갈을 좋아한 게 아니라 미갈이 다윗을 먼저 사랑했다고 나오는데.. 본의가 아니게 시집을 다시 갔다가 돌아온 뒤, 결국 다윗의 여러 아내들 중 랭킹 끄트머리로 밀려나면서 파경으로 갔구나. 인생 한번 참 파란만장했다.

Posted by 사무엘

2014/06/09 08:37 2014/06/09 08:37
, , ,
Response
No Trackback , 4 Comments
RSS :
http://moogi.new21.org/tc/rss/response/972

« Previous : 1 : ... 126 : 127 : 128 : 129 : 130 : 131 : 132 : 133 : 134 : ... 215 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/05   »
      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:
2712043
Today:
119
Yesterday:
1589