삽질하는플머

'분류 전체보기'에 해당되는 글 130건

  1. 오픈캡쳐에 대한 독백 4
  2. CrossKylix 갖고놀기
  3. Delphi web script 갖고 놀기 2
  4. Delphi web script 갖고 놀기 4
  5. PHP 에서 Int64 숫자값 문제

오픈캡쳐에 대한 독백

이런저런잡다구리/잡설
점심 먹고 델마당 눈팅하다 혈압 만땅 오름. 

더러운 국산 소프트웨어는 예의가 없다던 글이 멀쩡히 있는데 
주어가 없으니 인수업체에 대한 비난으로 해석하라.
아전인수도 참 가지가지.  
그 말이 성립하려면 오캡의 십년간의 노고에 대해 
위로 한마디쯤 하는 게 예의라는 거 진정 모르는 걸까. 

글의 행간을 자신의 의도에 맞추어 파악해야 한다고 강변하면서
그 멋지고 잘난 "관심법"을 왜 자기들에게는 못쓰지.  

저런 잡것들과 동업자라는 느낌에 
강좌 쓰고 세미나 하고 질문에 답하던
내 자신이 참 븅딱같다. 

뭐 어때. 내 블로그에 이런 글도 못적나.
보기 싫으면 오지 마. 
오프라인에서 항상 하는 얘기지만, 나 성격 별로 안좋아. 

착한 사람인 척 해봐야 다 벗겨먹고 
껍질만 남으면 퉤 뱉을 인간들 주제에 
댓글 달지 마. 꼴도 보기 싫으니까. 

CrossKylix 갖고놀기

탐구생활/Delphi
윈도+델파이 환경에서 리눅스용 실행파일을 만들 수 있다는 CrossKylix
http://crosskylix.untergrund.net 

페북의 자칭 컴맹님(타칭 컴퓨터맹주님)이 "70년대 미녀 배우와 지금 데이트하는 느낌" 라고 하셔서 호기심 급발동. 
당연한 이야기지만 Kylix가 필요하다. "Kylix 3 Open Edition" 을 사용해도 괜찮다는군. 
예전 볼랜드의 다운로드 링크는 거의 사라졌는데, 왠일인지 이 링크는 살아있다.
http://download.borlandforum.com/kylix/Kylix3Open/kylix3_open.tar.gz 
더 이상 라이센스 발급은 하지 않지만 CrossKylix와 사용은 가능하다. 
다운받아 적절한 곳에 압축을 풀자.  

crosskylix-110.zip 도 내려받아 압축을 풀고 setup.exe 를 실행시키자. 
설치는 편의상 C:\CrossKylix 에 하자. 




CrossKylix Installer 가 실행되면 아까  kylix3_open.tar.gz 의 압축을 풀어둔 폴더를 선택해준다. 



지원하는 델파이 버전은 6, 7, 8, 2005, 2006이다.
다만 2005 버전 이후로는 콘솔/웹 어플만 만들 수 있고, CossKylix 1.1.0 버전은 델 7에서만 테스트 되었다고 한다. 
델파이 7을 띄우고 CrossKylix가 설치된 폴더 아래 ideplugin 폴더에서 CrossKylix.dpk 패키지를 열어 인스톨 한다.



CrossKylix Options 창이 나타나면 CrossKylix 가 설치된 폴더를 다시 지정하고 OK를 눌러준다. 


 
이것으로 설치는 완료. "Hello World!" 를 출력하는 간단한 예제를 만들어보자.
File->New->Others 에서 Console Application을 선택. 

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;

begin
  WriteLn('Hello World!');
  ReadLn;
end.



델파이에서 F9를 눌러 실행하면 뭐 잘 돌아간다. 



이제 Project -> Build with CrossKylix 메뉴를 눌러보자. 



빌드 출력창에 리눅스 바이너리가 생성되었다는 메시지가 나타나면 성공!



이 바이너리를 리눅스(우분투 10.04 서버 LTS. 커널은 2.6.32)로 옮기고 실행시키면 짜잔~~



"Kylix 3 open edition" 이 GPL 2 로 배포되기 때문에 실행시 GPL 관련 메시지가 출력되기는 하지만, 아무튼 잘 돌아간다.


Kylix Open Edition 에서 콘솔 어플리케이션을 만들 때 나타나는 이 GPL 메시지에 대한 꼼수 하나를 덧붙이면, 이 메시지는 프로젝트 소스 내의 {$APPTYPE CONSOLE} 지시자에 반응한다. 따라서 이 지시자를 다음과 같이 수정하면 더 이상 GPL 메시지가 표시되지 않는다.

program Project2;

{$IFNDEF LINUX}
  {$APPTYPE CONSOLE}
{$ENDIF}

uses
  SysUtils;
                 
begin
  WriteLn('Hello World!');
  ReadLn;
end.



당연한 이야기지만, 이렇게 해도 리눅스에서 콘솔 입출력에는 아무런 문제가 없다. 



CLX 를 이용한 GUI 어플리케이션도 만들어 볼까 했는데... 윈도매니저가 깔린 리눅스 시스템이 주위에 하나도 없네. 
다음 기회에 갖고 놀아보기로 하고 오늘은 이만 취침~~


 
주의:
1. 프로젝트 경로명에 공백문자가 있으면 빌드에 애로사항이 꽃핀다.  
2. 64비트 윈도에서 CrossKylix를 C:\Program Files(x86)... 밑에 깔면 마찬가지로 애로사항이 꽃핀다. 
 
 

Delphi web script 갖고 놀기 2

탐구생활/Delphi
어떤 물건이든지 익숙해지려면 무조건 써 봐야 만든 사람의 의도를 알 수 있다. 
DWScript 로 무얼 만들어보면 좋을까 잠시 고민하다가 Learning WebGL의 첫번째 강좌를 만들어보기로 했다. 

문제는 이 강좌가 벡터와 행렬 연산에 자바스크립트용 3D라이브러리인 glMatrix.js를 쓰고 있다는 점인데, 이 부분은 그냥 DWScript의 asm...end 구문을 활용하는 방향으로 타협하자. 자바스크립트 완전 초보인 나로서는 "바보스러울만치 빠르다"는 평가를 받는 이 라이브러리를 DWScript로 다시 짠다고 그만큼의 성능을 낼 자신이 없으니까. 

암튼 뚝딱뚝딱 바꿔보자. 


<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>WebGL lesson-01 by pas2js</title>
  <script type="text/javascript" src="http://learningwebgl.com/lessons/lesson01/glMatrix-0.9.5.min.js"></script>

<script type='text/javascript'>

<%pas2js
procedure alert(msg: Variant); external;

var gl : Variant;
var shaderProgram : Variant;

var shader_fs : string =
  "precision mediump float; "+
  "void main(void) { "+
  "  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); "+
  "}";

var shader_vs : string =
  "attribute vec3 aVertexPosition; " +
  "uniform mat4 uMVMatrix; " +
  "uniform mat4 uPMatrix; " +
  "void main(void) { " +
  " gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); " +
  "}";

function get_fs_shader(ShaderScript: string): Variant;
begin
  Result := gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(Result, ShaderScript);
  gl.compileShader(Result);

  if not gl.getShaderParameter(Result, gl.COMPILE_STATUS) then
    alert(gl.getShaderInfoLog(Result));
end;

function get_vs_shader(ShaderScript: string): Variant;
begin
  Result := gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(Result, ShaderScript);
  gl.compileShader(Result);

  if not gl.getShaderParameter(Result, gl.COMPILE_STATUS) then
    alert(gl.getShaderInfoLog(Result));
end;

procedure initShaders()
begin
  var fragmentShader: Variant = get_fs_shader(shader_fs);
  var vertexShader  : Variant = get_vs_shader(shader_vs);

  shaderProgram := gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  if not gl.getProgramParameter(shaderProgram, gl.LINK_STATUS) then
  begin
     alert("Could not initialise shaders");
     Exit;
  end;

  gl.useProgram(shaderProgram);

  shaderProgram.vertexPositionAttribute := gl.getAttribLocation(shaderProgram, "aVertexPosition");
  gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

  shaderProgram.pMatrixUniform := gl.getUniformLocation(shaderProgram, "uPMatrix");
  shaderProgram.mvMatrixUniform := gl.getUniformLocation(shaderProgram, "uMVMatrix");
end;

var triangleVertexPositionBuffer: Variant;
var squareVertexPositionBuffer: Variant;

procedure initBuffers()
begin
  triangleVertexPositionBuffer := gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
  asm
    var vertices = [
0.0,  1.0, 0.0,
      -1.0, -1.0, 0.0,
1.0, -1.0, 0.0
];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  end;
  triangleVertexPositionBuffer.itemSize := 3;
  triangleVertexPositionBuffer.numItems := 3;

  squareVertexPositionBuffer := gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
  asm
    vertices = [
  1.0,  1.0, 0.0,
-1.0,  1.0, 0.0,
  1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  end;
  squareVertexPositionBuffer.itemSize := 3;
  squareVertexPositionBuffer.numItems := 4;
end;

var mvMatrix: Variant;
var pMatrix: Variant;
asm
  @mvMatrix = mat4.create();
  @pMatrix = mat4.create();
end;

procedure setMatrixUniforms()
begin
  gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
  gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
end;

procedure drawScene();
begin
  gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
  gl.clear(gl.COLOR_BUFFER_BIT or gl.DEPTH_BUFFER_BIT);

  asm
    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
    mat4.identity(mvMatrix);
    mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
  end;

  gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
  gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
  setMatrixUniforms();
  gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);

  asm
    mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
  end;

  gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
  gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
  setMatrixUniforms();
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
end;

procedure initGL(canvas: Variant)
begin
  try
    gl := canvas.getContext("experimental-webgl");
    gl.viewportWidth := canvas.width;
    gl.viewportHeight := canvas.height;
  except
  end;

  if not gl then
    alert("Could not initialize WebGL, sorry :-(");
end;
%>


function webGLStart() {
  var canvas = document.getElementById("gl-canvas");
  initGL(canvas);
  initShaders();
  initBuffers();

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.enable(gl.DEPTH_TEST);

  drawScene();
}
</script>

</head>
<body style="margin:10; overflow:hidden" onload="webGLStart();">
<canvas id="gl-canvas" style="border: none;" width="500" height="500"></canvas>
</body>
</html>



이 코드를 어제 소개한 JSCodeGenDemo 에 통째로 붙여넣고 Run 버튼을 눌러보자.



크롬이 기본브라우저로 되어있다면 (개발자라면 대부분 그럴 것이라 믿...) 웹GL 컨텍스트에 예쁘게 랜더링 된 삼각형과 사각형을 볼 수 있을 것이다. 




변환되어 나온 소스는 TObject와 Exception이 기본적으로 포함되어 그다지 아름답지는 않다. 
아무래도 DWScript의 진가는 객체로 되어있는 기존의 코드를 자바스크립트로 변경할 때 유용할 것이다. 
한마디로 표현하자면... 자바스크립트를 공부하려는 늙은 델파이 프로그래머에겐 알라의 요술봉 같은 물건이라고 할까...

오늘은 이정도로 마무리 짓고, 객체의 변환은 다음 기회에... 
 

Delphi web script 갖고 놀기

탐구생활/Delphi
DWScript 

개발자의 블로그는 여기

지원하는 델파이 최소버전이 2009이다. 터보델파이 이후로는 무거워서 손이 잘 안가게 되는데... 아무튼 핑계김에 미루어두었던 XE2 설치. 
 




업데이트 3까지 진행하고 환경설정을 익숙하게 맞추어준다. 




SynEdit SVN 설치. 

 
DWScript 개발자의 블로그에는 작년 12월 26일 크리스마스 선물로 SynEdit SVN에 패치를 올렸다는 글이 있다. 
http://delphitools.info/2011/12/26/christmas-present-for-synedit-users/ 

하이라이팅 속도가 많이 빨라졌다고 하고 무엇보다 DWScript의 예제가 이 버전을 기준으로 하니 이걸로 내려받아 설치하자. 

svn co https://synedit.svn.sourceforge.net/svnroot/synedit/SynEdit SynEdit



세상일이 다 그렇듯, 단박에 설치되는 법이 없다. 델파이의 컴파일러는 안시파일의 코드페이지를 시스템의 설정에 따라 판단하는 희안한 행동을 하기 때문에, 코드 내에서 유니코드를 사용한 경우 일일이 BOM을 붙여 UTF-8 임을 알려주어야 한다. SynEdit.pas, SynEditHighlighter.pas, SynEditSearch.pas, SynHighlighterJava.pas, SynHighlighterXML.pas 가 그러한데... 이렇게 해도 CASE문에서 이유없는 중복에러가 발생한다. 자세한 건 XE2에 좀 더 익숙해지면 알아보도록 하고, 일단 설치만 되도록 패치를 만들어 보았다. 




DWScript 테스트

dwscript-2.2 를 받아 압축을 푼다. XE용 패키지가 있으니 그대로 사용한다. 
데모를 살펴보니 Hello 라는 예제가 보인다. 열어보자. 

var s : String = ''Hello World!';
ShowMessage(s);



위와 같은 파스칼 스크립트를 입력받고 실행시키는 예제이다. 실행시키면 "Hello World!" 라고 찍힌 메시지박스가 나타난다. 재미있군. 
이제 오늘의 하이라이트! pas2js 를 갖고 놀아 보자.
 
http://delphitools.info/2011/09/28/taming-the-flock-with-object-pascal/ 

본문 내 링크에서 demo.zip 을 내려받아 압축을 푼다. JSCodeGenDemo.dproj 를 열고 컴파일하면 짜잔~~



이 프로그램은 인디의 idHTTPServer 를 사용해 독립 웹서버로 동작한다. <%pas2js ... %> 태그 사이에 파스칼 스크립트로 코드를 적어주면 이 부분을 자바스크립트로 변환해 클라이언트로 내려주게 된다. 과감하게 Run 버튼을 눌러보자. 



웹브라우저가 열리며 마우스 이동과 클릭에 반응하는 멋진 canvas 화면이 나타난다. 웹페이지의 소스보기를 하면 파스칼 스크립트가 자바스크립트로 변환되어 전송된 것을 볼 수 있다. 물론 브라우저를 띄우지 않아도 Compile 버튼을 눌러 변환된 자바스크립트를 얻을 수 있다. 

파스칼 스크립트 내 "asm .. end" 구문은 조금 별난 개념으로, 자바스크립트를 직접 호출하는데 사용된다.
간단한 예를 들어보자. 메시지 창을 띄우는 ShowMessage() 함수를 DWScript로 구현한다면 다음과 같이 할 수 있다. 

<%pas2js

procedure ShowMessage(msg: String);
begin
  asm
    alert(msg);
  end;
end;

ShowMessage('테스트야 테스트');
%>



위 내용은 다음과 같이 변환된다. 

function ShowMessage(msg) {
    alert(msg);
  };
ShowMessage("테스트야 테스트");



파스칼에서 외부 링크된 함수를 불러오는 것 처럼, external 구문을 써서 자바스크립트의 alert 함수를 직접 사용할 수도 있다. 

<%pas2js

procedure alert(msg: Variant); external;

alert('테스트야 테스트');
%>



변환된 내용은 다음과 같다. 

alert("테스트야 테스트");



이 외에도 문자열을 나타내는 따옴표를 쌍따옴표와 섞어 사용할 수 있는 등 델파이의 문법과는 약간씩 달라 헷갈리기는 하지만, 파스칼로 건드리는 HTML5 코딩이라는 점 만으로도 충분히 갖고 놀아볼만한 가치가 있다고 생각된다. 

아래 화면은 Delphitools.info 의 또 다른 예제를 위의 변환기로 컴파일해 이 블로그의 HTML편집기능으로 직접 써넣은 것이다. 
HTML5를 지원하는 최신 브라우저에서 무리없이 동작할 것이다. 실로 아름답지 않은가... (아이폰에서도 동작은 하는데 많이 느림...)




 

PHP 에서 Int64 숫자값 문제

탐구생활/WEB 관련
PHP의 최대 정수값은 다음 코드로 살펴볼 수 있다. 

echo PHP_INT_MAX;



이 값은 32비트에서는 2,147,483,647. 64비트에서는 9,223,372,036,854,775,807 이다. 하지만 윈도에서는 32비트건 64비트건 관계없이 2,147,483,647 이다. (참고링크 : http://www.pubbs.net/200902/php/3781-re-php-dev-casting-doubles-to-ints.html)
 
내 경우 게임 캐릭터의 사이버머니 또는 현금의 필드값은 BIGINT, 즉 Int64 형을 쓰고 있다. 비교에서 사용될 경우야 단순히 문자열로 간주하면 상관없지만, 이렇게 '돈'에 관련된 경우는 상황이 조금 다르다. 직접적으로 값을 박아넣는 것이 아니라 기존값에 대해 증가시키거나 차감시키는 방식으로 처리하는 '연산'이 필요하기 때문이다. 따라서 PHP의 정수값 한계는 문제가 된다. 

게다가 PHP는 큰 정수의 경우 자동으로 실수값으로 변환해 처리하게 된다. 정수 한계를 벗어나는 큰 수를 변수에 넣고 출력해보자.

$k = 703687441776631235523;

echo $k;
echo sprintf('%f', $k);



출력결과는

7.0368744177663E+20
703687441776631218176.000000



이처럼 입력값과 전혀 관계없는 부정확한 값이 찍히게 된다.

일단 떠오르는 해법은 두가지. 스토어드 프로시저를 써서 MySQL에서 현금값을 차감하는 함수를 만들고 이것을 호출하는 방법. 
두번째는 BCMath(http://kr2.php.net/bc), 또는 GMP(http://www.php.net/manual/en/book.gmp.php) 를 사용하는 방법.

GMP는 잘 모르겠고, BCMath의 경우는 우분투, 윈도용 WAMP, NAS 세군데 모두 번들되어있다. 따라서 이 녀석을 쓰자.

$m = bcadd("703687441776631235523", "1", 0);
echo $m . '<BR>';


 
출력결과는 다음과 같다.

703687441776631235524


 
bcadd 의 마지막 인자는 결과값에서 사용할 소수점 자릿수. 정수만 쓰려면 0을 준다. 
또는 bcscale() 함수로 전역적으로 설정할 수도 있다.

bcscale(0);
$m = bcadd("703687441776631235523", "1");
echo $m . '<BR>';


 
BCMath 에는 이 외에도 빼기, 나누기, 곱하기, 승수 처리함수가 내장되어있다. 두 숫자가 같은지 비교하는 bccomp 도 유용하다. 
이로서 DB에 들어있는 BIGINT 현금값을 문자열로 간주, BCMath로 비교후 차감한 뒤 그 결과값을 돌려줄 수 있게 되었다.