로그라이크류 개발을 위한 nForge 생성

Posted by NUL PROG. : 2010. 12. 4. 21:21

아직까지도 뭘 만들지 정해진게 없이 끄적이다보니... 제목도 못정했어요

그냥 R-LIKE 로 했습니다.


아직 SVN 생성이 안되는 듯.... 소스 계속 올릴 겁니다.

필요하신분은 알아서 받아가시되 GPL 라이센스입니다.

뭐 어차피 이걸 가지고 상용 어플을 만들어봐야 팔지도 못하니 서로서로 공개하면서 배워 나가는게 좋겠죠


윈도우즈 + SDL + 델파이 기반입니다.
SDL 기반이라 리눅스 포팅도 쉽게 될 듯.....

SDL 라이브러리는 LIBSDL
SDL 라이브러리 헤더는 SDL-JEDI 에서 받으면 됩니다.


글이 심심하니 현재까지 작업된 스샷 올립니다. (공개하지는 않았지만 Direct X 기반으로 만든 2007/04/02 - [PROG.] - 게임 제작의 전반적인 컨셈 보다 완성도가 떨어집니다. 거의 손을 안대다 보니 -_-;)



실행파일도 R-LIKE 개발 페이지 에서 받을 수 있습니다.

  

모달시 뒷 배경을 반투명으로...

Posted by NUL PROG. : 2010. 1. 8. 08:21

델파이 2007 기준입니다.

델파이 7 버전도 되는걸로 알고 있슴.


Application.OnModalBegin

Application.OnModalEnd 를 사용합니다.

OnModalBegin 에서 반투명 폼으로 스크린을 덮어 버리고, OnModalEnd 에서 폼을 닫는 거죠.



예전에... 휴대폰 대화박스가 뜰때 이런식이라 구현해 본 건에 알고보니 이미 이런 팁은 많이 나왔더군요. -_-;

정보가 흘러 넘처서 주체하지도 못할 지경의 세상이니 이런 소박한 꼼수들이야 뭐...

Dim Out the Main Form of an Application When Modal Form is Displayed

Modal폼을 띄울때 Disable되는 폼을 Gray톤으로 ...


소스 + 실행파일 포함입니다.


  

반올림 (Rounding)

Posted by NUL PROG. : 2007. 8. 16. 19:15
일반적으로 반올림이라 하면 특정 자리수가 4이하면 버리고 5이상이면 올리는것을 말하며, 이를 산술 반올림(Arithmetic Rounding) 이라 합니다. 하지만 델파이에서는 이 산술 반올림을 쓰지 않죠. (다른 언어는 레퍼런스를 참조해야 합니다. 모르겠다는 뜻 -_-;)

델파이에서 사용하는 라운딩 방법은 Banker's Rounding이라 불리는 넘으로, 1.5와 2.5는 둘 다 2로, 3.5와 4.5는 둘 다 4로 즉, 가장 가까운 짝수로 라운딩합니다. 이는 Arithmetic Rounding 에서 발생하는 편중 오차를 줄이기 위함입니다. 1,2,3,4는 버림 6,7,8,9는 올림을 하고 5를 모두 올림해버리면, 올림을 할때가 1/9 번 많아지게 되는 것이니까요.
즉, Round(1.5) + Round(2.5) = Round(1.5 + 2.5) 가 성립합니다.

물론 Banker's Rounding도 오차의 여지가 있으므로 Random Rounding(제멋대로 반올림 -_-) 이나 Alternate Rounding(교대로 반올림) 등을 쓰기도 합니다.

하지만, 간혹 산술적인 반올림(Arithmetic Rounding)이 필요한 때가 있습니다. 이때는 직접 만들어 써 줍니다.
Arithmetic Rounding Function function RoundA( X : single ) : Integer;
begin
   if val > 0 then result := Trunc(val + 0.5)
   else result := Trunc(val - 0.5)
end;


Default8087CW 와 Set8087CW($1B32); 로 델파이의 반올림 방법을 바꿀수 있긴 합니다만......
매우 비추천하는 방법입니다.
CPU의 컨트롤 워드를 조작하는 것이기 때문에... 다른 어떤 부분에서 영향을 받을 수도 있기 때문입니다.
  

특정 폴더와 파일들을 압축하기

Posted by NUL PROG. : 2007. 7. 13. 21:58
이번 팁은 팁이 아닌 엽기행각일 수도 있다. -_-;

파일 압축에 대한 고민

보통의 데이터 파일의 압축은 델파이에 포함된 ZLIB를 사용하면 손쉽게 TStream 객체를 이용하여 다양한 포멧의 데이터들을 압축할 수 있기에 즐겨 사용하고 있다. 다만, 어떤 요구에 의해 사용자가 일반 압축 프로그램으로 데이터를 풀고자 희망할 때, 그러면서 동시에 많은 파일과 폴더 압축이 되어야 할 때 고민이 생긴다. 과연 이 하나의 기능을 위해 압축 컴포넌트를 설치하여 써야 한단 말인가. 특히나 자주 쓰지 않는 기능이라면, 언제나 최소한의 소스를 유지하고픈 잠재적 욕구에 의해 고민을 하지 않을 수 없다.

순간 보이는 빵 아이콘

사용자 삽입 이미지
빵집이라는 무료 공짜 공개 소프트웨어가 있다. 회사에 압축 프로그램 사달라고 떼쓰기도 거시기 하기에 납품하는 PC에 늘 설치하는 이 고마운 빵집. 그렇다. 언제나 PC와 윈도우즈 및 기본적은 프리웨어를 늘 설치해서 납품해왔던 것이다. 그렇다면, 걍 빵집을 쓰면 되겠네 -_-; 빵집을 열어 보았더니 스크립트를 제공하고 있다. 공개 소프트웨어를 만들고 배포하는 분들에게 무한의 공경심과 고마움을 느껴야 한다는 절대적 사실을 또 한 번 깨닫게 된다.

빵집 스크립트 파일 포멧

  1. 확장자는 bsz 이다.
  2. 세미콜론이 주석이다.
  3. Mode=Compress는 압축, Extract는 해제이다.
  4. ArchiveFile=압축 파일 경로+이름이며 <DATE>는 자동으로 날짜를 파일 이름에 붙여주고 <INDEX>는 동일 이름의 파일이 존재하면 파일 이름에 숫자를 추가한다.
  5. Progress.Caption=진행상황 윈도우의 캡션
  6. Progress.Text=진행상황 윈도우의 텍스트 메세지
  7. Files.RootPath=압축할 파일의 경로
  8. Files.Count=압축할 파일+폴더의 합
  9. Files.0=파일 이름 혹은 폴더 이름
  10. Files.1=파일 이름 혹은 폴더 이름
  11. Files.2=파일 이름 혹은 폴더 이름
  12. Extract.Path=압축을 해제할 때의 대상 경로
  13. After.Run=압축/해제의 완료후에 실행될 파일
구구절절이 설명을 달아 놓았지만 그냥 빵집에서 스크립트 생성해보고 그 파일을 읽어 보면 감이 잡힐 것이다 -_-;
사용자 삽입 이미지

빵집 스크립트 편집 화면


스크립트 파일을 생성해서 동작시키자

간단한 파일 압축 함수 예제(허접하니 고쳐서 쓰시라) procedure BackUp(ABackupFolder: String);
var
  szPath: String;
begin
  szPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
  with TStringList.Create do
  try
   Add(';BreadZip Script Version 1');
   Add('Mode=Compress');
   Add('ArchiveFile=' + IncludeTrailingPathDelimiter(ABackupFolder) + 'EX_<DATE><INDEX>.zip');
   Add('Progress.Caption=백업하련다');
   Add('Progress.Text=금방 되니 참고 기둘려라.');
   Add('Files.RootPath=' + szPath);
   Add('Files.Count=3'); // 3개를 압축
   Add('Files.0=config'); // config 폴더
   Add('Files.1=data'); // data 폴더
   Add('Files.2=EX.ini'); // ex.ini 파일
   SaveToFile(szPath + 'Ex_Compress.bzs');
   ShellExecute(0, 'Open', PChar(szPath + 'Ex_Compress.bzs'), '', '', SW_SHOW);
  finally
   Free;
  end;
end;
압축 해제할 때도 마찬가지의 방식으로 하면 된다.

자~ 이제 남은 건 고객의 PC에 무조건 빵집을 설치하는 일만 남은 것이다. 후후.....;
  

적목 효과 제거 프로그램을 만들어보자

Posted by NUL PROG. : 2007. 5. 29. 23:12
적목현상이란?

어두운 곳에서 사람의 동공이 확대되었을 때 플래시를 터트리며 사진을 찍게 되면, 플래시 빛이 이 확대된 동공을 통과하여 망막 뒤의 모세혈관에 반사되고 이 반사된 붉은빛이 다시 카메라의 렌즈로 들어와서 빨간 눈으로 사진이 찍히게 되는데 이를 적목현상이라 한다.

이를 피하려면 ......
  1. 동공이 커지지 않게 조명을 밝게 하거나 (혹은 밝은 곳에서만 사진을 촬영 -_-;)
  2. 플래시의 빛이 반사되는 것이기에 피사체를 중심으로 플래시와 렌즈의 각도를 크게 하거나 (즉 렌즈와 플래시의 거리를 떨어뜨리거나 별도의 조명을 사용)
하는 방법이 있다.

일반적으로 디지털 카메라는 그 크기가 매우 작아서 특히 이런 현상이 자주 발생한다.

아무튼 이를 보정하는 프로그램을 작성해보도록 하겠다. 일단 완성품을 보도록 하자

사용자 삽입 이미지

이번에도 집사람의 사진을 무단 도용하였다 (미안 -_-;)



사용자 삽입 이미지

마우스를 드래그하면 사각 영역이 그려지고,



사용자 삽입 이미지

드래그가 끝나면 선택 영역의 적목현상으로 나타난 빨간 눈을 대충 바꿔 준다.



사람이 영역을 선택해 주기 때문에 시퀀스가 단순하다. 만약 이를 완전 자동화한다면, 사람의 얼굴을 찾고 눈을 찾는 알고리즘이 들어가야 하는데, 이게 쉽지 않고 구현한다 하더라도 어느 정도의 오류 발생을 감수해야 한다.

아래와 같이 쉽게 쉽게 하도록 하자 -_-ㅋ
  1. RGB 칼라맵의 R 강도를 구하고 그 값이 일정 수치 이상인 경우를 찾는다.
    일정 수치라는 건 다양한 테스트로 아무거나 정하거나, 평균값을 구하거나, 평균값에 가중치를 약간 주거나 맘에 드는 걸로 하자.
    예제에서는 그냥 적당한 숫자를 넣었다.
    R 값의 강도 (Redness) 구하기 function SubGetRedness: Double;
    begin
      if r = 0 then Result := 0
      else Result := (r - g + r - b) / r / 2;
    end;
  2. R의 강도가 일정 수치를 넘으면 그 R 값을 G, B 값의 가장 작은 값으로 대체 해준다.
    이때 너무 빨간 빛이 확 줄어버릴 수 있기 때문에 적당한 가중치를 적용하여 기존 R 값을 넣어준다.
    예제에서는 8:2로 넣었다.
    R 값을 8:2 로 보정하는 식 r := Trunc(Min(g,b) * 0.8 + r * 0.2);

너무 간단하게 끝나 버렸다......;

눈이 아닌 부분의 픽셀을 보정하지 않게 막으려면,
R 값이 일정 수치 이상일 때 기하학적인 정보로 눈동자의 중심을 찾고 눈동자의 중심에서 멀리 떨어진 픽셀을 제외 시키는 방법도 좋겠다.
기하학적인 정보로 눈동자를 찾기 어렵다면, 픽셀 좌표의 분포를 검사해서 대략 적인 중심을 구할 수도 있다.

좀 더 부드러운 느낌이 들도록 보정 하려면,
적목효과 보정 주변 픽셀에 블랜딩을 주거나 혹은 블러 효과를 넣는 것도 좋을 것이다.

  

델파이는 객체지향적인 언어인가?

Posted by NUL PROG. : 2007. 5. 27. 13:46
사용자 삽입 이미지
유명한 델파이 동호회에서 이런 이야기가 잠시 흘러나온 적이 있다.
내 생각을 말하자면 "객체지향적이든 아니든 중요하지 않다."이다
물론 동문서답 격인 대답이므로 답글을 달진 않았다. (요즘은 인터넷 공간에 엉뚱한 글을 답글로 쓴다는 것은 상당한 용기가 있어야 한다.)

우선 객체지향(OOP : Object-Oriented Programming)적인 언어라는 것이 무엇을 의미하는지 알아야 한다.

Class, Object, Method, Message 등으로 구성되어 Encapsulation, ,Abstraction, Polymorphism의 특성이 있는 언어라 할 수 있겠다. ( 위키피디아 에서 따왔는데, 한글 위키라 그런지 설명이 좀 부실하다. 10년 전인가 이 개념을 이해하고자 3-4권의 책을 반복으로 정독하고 10여 권을 책을 훑어 본 적이 있음을 기억할 때 그리 간단하게 규정하기는 어렵다고 본다. 이것은 범위가 넓은 거대한(?) 이론이기 때문이다. )
아무튼 대강 그런 뜻이라 여기고 넘어가도록 하자.

항상, 그 이론보다 중요한 것은 그 이론이 발생하고 발전하게 된 동기이다.
즉, 왜 이러한 이론이 필요한지, 무엇을 위한 이론인지가 중요하다.

누가 이론이 아니랄까 봐 어려운 말들로 잔뜩 설명이 되어 있는 일도 있지만,
간단히 이야기하면 원하는 기능의 코드를 빠르고 유지보수가 쉽도록, 추후의 작업에 재사용 가능하도록. 최초 설계 단계에서의 편리성과 보다 정확한 검증을 위해......
한마디로, 생산성의 향상을 위한 것이다.

이렇게 본다면, 어떠한 언어가 얼마나 OOP인가를 따지는 것보다는 어떠한 언어가 생산성이 있는가를 따지는 것이 더 의미가 있다고 본다. 비록 일반적 이론상의 OOP에 미치지 못하는 부분이 조금 있다손 치더라도 그걸로 인해 생산성이 더 향상된다면 굳이 이론상의 OOP를 억지로 구겨 넣어야 할 필요가 없다.
물론 여기서 말하는 생산성은 단순히 빠른 작업 속도만이 아닌 편리성, 안정성을 추가한 개념이다. 뭐 사실 그것이 빠른 작업 속도에 영향을 끼치긴 마찬가지이지만.....

예를 들면, 폼 기반의 애플리케이션 구조를 가진 델파이의 VCL은 객체지향적이라고 하기엔 부족한 면이 있지만, 이는 매우 편리한 UI 제작을 위한 DESIGN 개념을 위한 것이고 그만큼의 충분한 생산성을 향상시켰기 때문에 객체지향적이지 못하다는 것이 큰 문제가 되지 않는다는 것이다. 같은 이유로 모호한 다중상속을 좋아하지 않는다.

또 한가지,

객체지향이라는 것은 방법이나 구조에 대한 이론이기에 그 언어가 크게 중요하지 않다.
즉 어느 정도 객체지향적으로 프로그래밍할 수 있는 언어라면 OOP 이론을 적용하여 프로그래밍하는 것 자체가 중요하지 언어가 중요한 것이 아니다.

실제로 class만 있을 뿐이지 C++ 인지 C 인지 구별이 안 되는 코드는 사방에 널려 있다.

델파이의 예로 들면 VCL의 폼 기반 애플리케이션 설계는 객체지향적이라 보기 미흡하지만 독립된 몇 가지의 클래스로 데이터를 관리하고 폼은 단지 보여주기만 할 뿐...... 의 방식으로 코딩한다면 매우 훌륭한 객체지향적 프로그래밍을 할 수 있다.

요약하면... (구세대 교육을 받은 결과 인지, 요약을 하지 않으면 끝맺음이 뭔가 부실한 느낌이다. -_-; )
  • OOP를 따르는 것보다 OOP의 목적을 성취하는 것이 더 중요하다.
  • 이를 위해서는 사용하는 언어가 얼마나 객체지향적인가 보다는 개발자가 얼마나 객체지향적으로 프로그래밍할 수 있는가가 중요하다.
  
일반적으로 컴퓨터에서 사용하는 색상은 RGB기반입니다. 빨강, 녹색, 파랑의 빛으로 모든 색을 표현할 수 있죠. 윈도우 그래픽에서는 이런 색상을 32Bit 정수로 표현합니다.
파랑: $00FF0000 녹색 $0000FF00 빨강 $000000FF 이런 식으로 표현됩니다. 좌측부터 읽는다고 한다면 BGR의 순서가 되지요.


통상적으로 HSV (Hue, Saturation, Value of Intensity) 칼라맵이라 칭하는 것은 RGB 기반이 아닌 미술 시간에 배우는 색상, 채도, 명도입니다. 좀 더 구체적으로 이야기하면,
색상은 0~360도의 각도로 표현되며 120도 간격으로 빨강, 녹색, 파랑이 배치되어 있고 사이 사이에 혼합된 색이 존재합니다.
채도는 각 색상이 얼마나 순수한가를 따지는 %이고, 명도도 밝기를 나타내는 %입니다.
이를 수학적으로 표시하면 theta, r, z로 이루어지는 3차원 극좌표가 되며 뒤집힌 원뿔 모양으로 나타납니다.
아무튼, 이걸 사용하는 색상 선택 창을 만들어봅시다.


RGB <-> HSV 간의 변환 식은
http://www.eggcentric.com
http://www.delphipages.com/threads/thread.cfm?ID=133113&G=133111 를 사용하였고, HSV 데이터를 아래와 같이 규정하였습니다.
HSV 데이터를 위한 레코드 TColorHSV = record
  H: Single; // 0..1
  S: Single; // 0..1
  V: 0..255;
end;
V 를 굳이 0..255로 선언한 이유는 RGB <> HSV 간의 변환에 연산 횟수를 줄일 수 있기 때문이고 큰 의미는 없습니다.


단순히 요것만 하기에는 아쉬운 관계로 몇 가지 함수를 추가했습니다.
출력속도의 향상을 위해 델파이 TBitmap의 ScanLine 을 사용한다면 색상이 RGB 순서로 되어 있는지 BGR 순으로 되어 있는지 확인해야 합니다. (조무영님의 비DX 강좌) 최초에 현재 그래픽 카드가 RGB로 인식하는지 GBR로 인식하는지 확인하고 Scanline 사용 시에는 CheckRGBMode를 써서 RGB이면 GBR로 바꾸어 줍니다.
RGB , BGR Conversion

function GetRGBMode: Boolean; // RGB, BGR 중에서 어느쪽이 지원되는지 알아본다.
var
  P: PDWORD;
begin
  with TBitmap.Create do
  try
    PixelFormat := pf32bit;
    Width := 1;
    Height := 1;
    Canvas.Pixels[0,0] := clRed; // 붉은 색으로 칠해주고...
    P := ScanLine[0];
    Result := (P^ and $FF = 0);
  finally
    Free;
  end;
end;

function SwapRGBBRG(const RGB: TColorRef): TColorRef;
asm
  ROL EAX, 8; // ABGR -> BGRA
  XOR AL, AL; // BGRA -> BGR0
  BSWAP EAX // BGR0 -> 0RGB
end;

function CheckRGBMode(const RGB: TColorRef): TColorRef;
begin
  if IsRgbMode then Result := SwapRGBBRG(RGB)
  else Result := RGB;
end;




임의의 배경색을 사용할 때 검은색 혹은 흰색의 글자 색을 사용합니다. 이때 검은색 글자로 써야 잘 보일지 흰색 글자로 써야 잘 보일지를 아래의 함수로 확인합니다.
function IsDarkColor(const hsv: TColorHSV): Boolean;
begin
  Result := (hsv.V < 140.0) or // Lightness
            ((hsv.h < 0.07) and (hsv.s > 0.60)) or
            ((hsv.h > 0.93) and (hsv.s > )) or // Hue Red
            ((hsv.h > 0.60) and (hsv.h < 0.78) and (hsv.s > > 0.65)); // Hue Blue
end;
function IsDarkColor(const AColor: TColor): Boolean;
var
  hsv: TColorHSV;
begin
  RGB2HSV(AColor, hsv);
  Result := IsDarkColor(hsv);
end;



두 가지의 혼합된 색상을 구하는 데 쓰이는 함수입니다. (HSV 와는 관계가 없지만 간혹 쓰이는 함수인지라 함께 넣었습니다.
Yurii Zhukow (http://www.infoteh.ru/yzhttp://www.swissdelphicenter.ch/torry/showcode.php?id=1832
function MixColors(FG, BG: TColor; T: byte): TColor;
var
  r,g,b: byte;
begin
  R := MixBytes(FG and 255,BG and 255,T); // extracting and mixing Red
  G := MixBytes((FG shr 8) and 255,(BG shr 8) and 255,T); // the same with green
  B := MixBytes((FG shr 16) and 255,(BG shr 16) and 255,T); // and blue, of course
  Result := r + g shl 8 + b shl 16; //finishing with combining all channels together
end;



윈도우즈 칼라 데이터 (DWORD, COLORREF)를 HTML 형식의 문자열로 변환하는 함수입니다. 이걸 쓰면 알아보기가 더 편하죠.
function ColorToRGBString(const Color: TColor): String;
var
  c: ColorRef;
begin
  c := ColorToRGB(c);
  FmtStr(Result, '#%.2x%.2x%.2x', [GetRValue(c), GetGValue(c), GetBValue(c) ]);
end;
function RGBStringToColor(const RGBStr: String): TColor;
var
  r, g, b: Byte;
  v: DWORD;
begin
  v := StrToIntDef('$'+StringReplace(RGBStr, '#', '', []), 0);
  r := $FF and (v shr 16);
  g := $FF and (v shr 8);
  b := $FF and  v;
  Result := RGB(r,g,b);
end;



이렇게 기본 변환 함수들을 꼼수 + 구글링으로 만들었습니다. 이젠 이걸 사용해서 칼라맵이 펼쳐지는 윈도우 컨트롤을 만들어 봅시다. TCustomPanel을상속 받아서 만들었습니다.
사용자 삽입 이미지

좌측 정사각형의 X 는 Hue, Y 는 Saturation 오른쪽 직사각형의 Y 는 Intensity 값 입니다. 각 좌표값 그대로의 HSV 를 RGB 로 바꾸어주면 되죠. 더 신경을 써서 만든다면 사용자 마음대로 HSV 각 항목의 좌표를 바꿀 수도 있겠죠.
256*256 + 256개의 점을 찍는 것과 같아서 속도의 향상을 염두에 두고 FSelBmp, FBarBmp: TBitmap; 에 미리 그린 후, Paint 프로시저를 override 하여 현재 색상의 위치를 그렸습니다.


이젠 이걸로 최종 목표로 하는 색상 선택 창을 만들어 봅시다.
사용자 삽입 이미지

32 개의 전역 배열로 사용지 지정 색을 만들고, 이를 우측에 배치했습니다. 이 버튼을 클릭하고 색상을 선택하면 해당 배열의 사용자 지정 색이 선택한 색상으로 바뀌게 됩니다.


아래의 함수들로 사용자 지정 색을 얻거나 바꿀 수 있고, 이를 파일로 저장하고 읽을 수도 있습니다. 굳이 파일로 쓰지 않아도 전역 변수이기 때문에 프로그램 종료 시 까지 값이 저장되어 있습니다. (REGISTRY사용을 극도로 싫어하기 때문에 보통의 경우 INI를 씁니다. 특히 다른 INI 파일에 함께 쓸 수 있기에 선호합니다.)
function GetCustomColors(const Index: Integer): TColor;
procedure SetCustomColors(const Index: Integer; const AColor: TColor);
procedure LoadCustomColorsFromINI(const INIFileName: string);
procedure SaveCustomColorsToINI(const INIFileName: string);



폼 파일(*.dfm)이 없이 동작하도록 하는 팁을 적용했습니다.
(DFM을 사용하지 않고 폼(TForm의 상속) 사용하기)
항상 Owner 폼의 앞에 있도록 다음과 같이 CreateParams 를 override했습니다.
procedure TJnColorDlg.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if (Owner <> Nil) and (Owner is TForm) then Params.WndParent := TForm(Owner).Handle;
end;



사용법은 일반 다이얼로그 쓰듯이 하면 됩니다. uses 에 JnColorDialog 를 추가하고
예제 with TJnColorDlg.Create(Self) do
try
    if Execute(CurrentColor) then
    begin
        ... := Selected;
        ...
        ...
    end;
finally
    free;
end;



다운로드
  

화면 그리기 프로그램을 만들어보자.

Posted by NUL PROG. : 2007. 5. 8. 20:41
설명이 귀찮으니 일단 어떤 걸 만들려 하는지 보자.

클릭시 확대

왼쪽 마우스버튼은 빨강색 펜 오른쪽 버튼은 파란색 펜으로 그린다



델파이 7 pro, Graphics32를 사용하였다. 원래 이런 글은 TBitmap의 Scaline으로 포인터 써가며 픽셀 연산하는 모습을 보여주어야 뽀다구가 나지만……. 상당히 귀찮은 작업이므로. 그냥 라이브러리를 사용했다. 당연히 소스를 컴파일해보려면 이 라이브러리를 깔아야 한다.



제작 시퀀스

  1. 화면 전체를 캡쳐한다.
  2. 캡쳐한 이미지를 뿌린 윈도우을 최상단에 위치시킨다. 캡쳐한 이미지로 뒤덮인 윈도우이므로 마치 실제 데스크톱 화면이 그대로 있는 것처럼 보인다. -_-;
  3. 선을 그리기 위해 브러쉬 비트맵을 생성한다. 그냥 gdi를 이용해도 되지만 이렇게 해야 추후에 다양한 효과를 넣을 수 있다.
  4. 캡쳐한 이미지 위에 레이어를 올려놓자. (레이어라는 개념은 포토샵에 나오는 것 같지만 사실상 프로그래머에게 더 중요하다. 그래픽 편집 툴의 거의 모든 효과들은 이미지들의 비트 연산으로 이루어지는데 이를 위해 이미지들을 레이어 별로 구분시켜 놓고 원하는 효과에 따라 알맞은 알고리즘을 적용하여 연산을 시키는 것이다. 그러니까 결국은 포토샵과 같군요....;
  5. 윈도우의 마우스 입력에 따라 아까 만든 레이어에 마음껏 그리자.
  6. 형광 펜 효과 같은 걸 주려고 알파 브랜딩을 넣어야 하지만 Graphics32 가 알아서 해주므로 코딩이 너무 쉽다. 레이어 관련 클래스들도 이미 다 들어가 있으니 더더욱 손 델 필요가 없다. 왠지 거저먹는 기분이다 -_-;
  7. ESC 를 누르면 종료가 되게 하자.



너무 성의가 없어 보이니 -_-; 좀 더 자세히 비비고 들어가 보자

  1. 화면 캡쳐
    반투명 윈도우들을 캡쳐 하기 위해서 CAPTUREBLT 의 옵션을 준다. 델파이 7만을 사용하는 늘보는 이런 게 있는 줄도 몰랐다 ㅜㅜ (Daum 카페 다림방소프트웨어공작소 의 운영자가 일러 주셨다.)
    함수로 만들어 봤다 procedure GetDesktopScreen(ABitmap: TBitmap32);
    const
      CAPTUREBLT = $40000000;
    var
      Wnd : HWND;
      hdcScreen: HDC;
    begin
      ABitmap.SetSize(Screen.Width, Screen.Height);
      Wnd := GetDesktopWindow ;
      hdcScreen := GetWindowDC(Wnd);
      try
        BitBlt(ABitmap.Handle, 0,0, Screen.Width, Screen.Height, hdcScreen, 0, 0, SRCCOPY or CAPTUREBLT);
      finally
        DeleteDC(hdcScreen);
      end;
    end;
  2. 브러쉬를 만들고자 알파 채널 비트맵을 읽어서 색상을 입혔다. 여기선 알파 채널이 그냥 검은색 흰색뿐이지만 좀 더 보완해서 넣는다면 좀 더 부드러운 펜을 만들 수도 있다. 다만, 화면 그리기 용도는 이걸로 충분하니까 여기까지만 했다.
    흑백으로 이루어진 비트맵에 색상을 넣는 함수 procedure MakeColor(const Bmp: TBitmap32; AColor: TColor32);
    var
      pc: PColor32;
      i: Integer;
      r,g,b,a: byte;
    begin
      pc := Pointer(Bmp.Bits);
      for i:=0 to pred(Bmp.Width * Bmp.Height) do
      begin
        Color32ToRGBA(pc^, r,g,b,a);
        if a > 1 then pc^ := AColor;
        Inc(pc);
      end;
    end;
  3. 마우스 입력에 따라 브러쉬로 선을 그려야 한다. 선 그리기 알고리즘에 대해선 10년 전에 어렴풋이 공부한 것 같기도 한데……. 그걸 기억하기도 책을 찾기도 힘겨워서 Graphics 32 내부의 라인 그리는 루틴을 카피했다. 루 틴을 죽 보니 왠지 낯이 익은 것 같기도 하다 -_-;
    브러쉬로 그리기 procedure DrawHorzLine(Dest, Brush: TBitmap32; X1, Y, X2: Integer);
    procedure DrawVertLine(Dest, Brush: TBitmap32; X, Y1, Y2: Integer);
    procedure DrawLine(Dest, Brush: TBitmap32; x1,y1,x2,y2: Integer);

    요녀석들이다.


나머지 필요한 것은 사용자의 편의를 위한 부가기능일 것이다. (사실은 이게 더 고되고 험난한 일이다. )

혹시라도 이걸 사용할 곳이 있다면 출처를 밝히고 마음껏 쓰시라.


소스 및 데모 다운로드
  

가상키보드 (화면키보드)를 만들어보자

Posted by NUL PROG. : 2007. 4. 29. 18:47

가상 키보드(화면 키보드)란??


 화면에 키보드 형상을 그리고 그걸 클릭해서 실제 키보드를 타이핑하는것과 똑같은 효과를 얻기 위한 프로그램. 키보드가 없는 터치패널 시스템과 같이 키보드를 쓰기 어려운 상황에서 사용된다.

기술적 어려움

  1. 마우스 입력 후킹해서 키보드 입력메시지를 보내야 함.
  2. 키보드의 키 입력 상태(IME의 상태 CAPS_LOCK, NUM_LOCK 등등) 감시하고 있어야 함.
  3. 가상키보드의 자판을 클릭 시에도 원래의 애플리케이션에 포커스가 머물러 있어야 함
  • WH_MOUSE로 후킹을 하게 되면 마우스 입력을 취소시키더라도 포커스가 변경이 되어버리는 문제가 있다. 즉 후킹 전에 이미 포커스 이동 명령이 나가 버린다는 점. 따라서, 이를 방지하고자 메시지 후킹을 해야 할까 생각했지만, 다행히도 윈도우 2000 버전 이후에 추가된 WH_MOUSE_LL이라는 녀석이 있다.
  • 이 녀석은 마우스 입력이 들어가자마자 가로채 버린다. 근원적으로 마우스의 입력을 막을 수 있다는 뜻이다. 또한, 애초에 포커스가 이동하지 않기 때문에 한글 조합도 신경을 쓸 필요가 없다. 물론 윈도 2000 버전부터 지원한다는 것이 꺼림칙하긴 하지만, 늘보가 만드는 프로그램은 언제나 윈도 2000 이상을 요구하므로, 별 상관이 없다 -_-;
  • 사실 델파이 7에는 WH_MOUSE_LL 가 정의되어 있지 않기 때문에 전혀 모르고 있었는데, 도움말 파일을 뒤적거리다가 우연히 발견했다. 문제는 WH_MOUSE_LL 이게 값이 얼마 인지 알 수가 없어서 WH_MOUSE_LL = 14 라는 걸 찾으려고 구글을 이용할 수밖에 없었다.
  • 기타 IME 및 키보드의 상태 감시는 소스가 첨부되어 있고 검색하기도 쉽기 때문에 넘어가야겠다. (사실은 얼른 집에 가야 함 -_-;)
  • 포커스된 윈도우에 메시지를 보내는 방식을 쓰지 않고 keybd_event 를 사용했다. 이게 코딩하기 쉽기 때문이다 (귀찮은 걸 싫어하는 늘보임 -_-;)

예제 프로그램과 소스

  1. 원본 프로그램은 키보드의 모든 기능을 집어넣었지만, 여기선 일부만 빌려서 넷핵 플레이용 키보드를 만들었다. NUM 키 누르기가 영 불편하기에 만든 것이다.
  2. 그런데, 만들고 나서는 별로 쓰지는 않고 있다...;
  3. 혹시라도 이걸 사용할 곳이 있다면 출처를 밝히고 마음껏 쓰시라.
  4. 원본 프로그램에 개인적인 잡다한 라이브러리가 많아서 그걸 삭제하고 다시 컴파일하여 올린다.

예제 실행 프로그램 + 소스

  

간편한 Hooking - JOURNAL HOOK

Posted by NUL PROG. : 2007. 4. 29. 15:34
애플리케이션제작 시 간혹 실행 중의 마우스와 키보드의 상태를 알고 싶을 수가 있다.

 이럴 경우 SetWindowsHookEx란 녀석을 사용하여 해당 애플리케이션 혹은 모든 입력에 대하여 소위 Hooking란 것을 하게 되는데 다소 귀찮은 문제점이 있다.

 전역으로 후킹을 하려면 DLL을 사용해야 하기 때문이다.

 그러나 WH_JOURNALRECORD를 사용하게 되면 실행 프로그램 내에서 마우스 키보드의 후킹이 가능하다 !!

그러나,

 이녀석은 다른 Hooking과는 차이가 많은 엄밀히 얘기하면 Hooking이라 부르기 어려운 녀석이다.

 흔히 매크로라고 하는 것(사용자의 입력을 저장했다가 그대로 실행하는)을 위해 만들어진 듯한데, 그러다 보니 Hooking을 하는 게 아니라 메시지 큐의 메시지가 어떤 것들이 들어가 있나 하는 걸 그저 볼 수 있을 뿐이다. 따라서 후킹처럼 마우스 입력을 차단하거나 하는 기능은 할 수가 없고, 실시간으로 광범위한 메시지를 가져오기 때문에 그 데이터의 종류와 범위도 제한적이다.

 그래도, 언제나 선호하는 간단한 방법으로 마우스/키보드의 입력을 탐지할 수 있기 때문에, 나름 쓸모가 있지 않을까 싶다.

 이런 저런 테스트도 해보고 싶지만, 언제나 그렇듯이 이런 OS 의존적인 API는 그다지 값어치가 있다고 여기진 않기에, 나중에 심심해지면 한번 해보리라 생각을 정리하고 끝을 내야겠다.

 구글에서 SetWindowsHookEx,  WH_JOURNALRECORD, WH_JOURNALPLAY를 찾아 보면 관련 글이 부지기수로 많이 나온다.

 흔치않은 델파이 소스니 아랫것만 링크를 걸어놔야겠다.;


  

Mersenne Twister Random Generator

Posted by NUL PROG. : 2007. 3. 31. 16:22

Mersenne Twister

A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator.

home page

original c source

Translated to OP and Delphi interface added by Roman Krejci (6.12.1999)

수학이라 잘 모르겠습니다
그저 가져다 쓸뿐 -_-;;;
Seed 값을 조절 하면 (좀 크게...) 아주 만족 스럽습니다.
  
 «이전 1  다음»