$jekyll new sitename

로 새로운 사이트를 만들 때 아래와 같은 에러가 발생했다.


Bundler: ruby: No such file or directory -- /usr/lib/ruby/gems/2.3.0/gems/bundler-1.16.1/exe/bundle (LoadError)


$gem env

로 환경설정을 보면 경로가 아래와 같이 나온다.

/var/lib/gems/2.3.0


해당 경로로 심볼릭 링크를 걸어주거나, jekyll 설정을 변경하면 해결된다.




Django에서 MySQL이나 MariaDB를 사용할 때 해당 데이터베이스가 Strict Mode가 아니면

"MySQL Strict Mode is not set for database connection 'default'" 라는 경고가 발생한다.




프로젝트명/settings.py의 DATABASES 설정 부분에서 OPTIONS에

'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",

를 추가하면 된다.





참고 : http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict




html5 canvas를 사용할 때 자바스크립트(javascript)로 여러 줄 텍스트(multiline text)를 표시할 방법이 없어서 함수를 만들어보았다.


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
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
 
ctx.font="15px Consolas";
drawTextBox(ctx, "다람쥐 헌 쳇바퀴에 타고파\n다람쥐 헌 쳇바퀴에 타고파"1001001701.2)
 
function drawTextBox(ctx, text, x, y, fieldWidth, spacing) {
  var line = "";
  var fontSize = parseFloat(ctx.font);
  var currentY = y;
  ctx.textBaseline = "top";
  for(var i=0; i<text.length; i++) {
    var tempLine = line + text[i];
    var tempWidth = ctx.measureText(tempLine).width;
 
    if (tempWidth < fieldWidth && text[i] != '\n') {
      line = tempLine;
    }
    else {
      ctx.fillText(line, x, currentY);
      if(text[i] != '\n') line = text[i];
      else line = "";
      currentY += fontSize*spacing;
    }
  }
  ctx.fillText(line, x, currentY);
  ctx.rect(x, y, fieldWidth, currentY-y+fontSize*spacing);
  ctx.stroke();
}
cs





fillText()가 한 줄 짜리 텍스트만 출력할 수 있으므로 이를 여러 번 써서 멀티라인 텍스트필드처럼 보이도록 만드는 것이다.


코드의 동작 방식은 아래와 같다.

1) 임시변수(tempLine)에 쓸 문자열을 한개씩 더한다.

2) 더하면서 캔버스 컨텍스트의 measureText()를 이용하여 너비를 재고, 이것이 지정된 텍스트필드 너비를 넘었을 경우 한 줄을 fillText()로 화면에 그린다.

3) 매개변수로 입력받은 행간격 비율(spacing)만큼 아래로 간격을 띄워서 1)부터 반복한다.


1)에서 개행문자('\n')을 만났을 경우에도 줄바꿈을 한다.




전체 소스코드는 아래 링크에 업로드하였다.

https://github.com/tibyte/algorithms/tree/master/html5canvas-textfield





실행결과는 아래와 같다.







OpenGL로 외부 이미지파일을 읽어와서 출력할 때

glDrawPixels()함수를 쓰는 방법과 텍스쳐(texture)를 사용하는 방법이 있는데,

glDrawPixels()는 그릴 때마다 메인 메모리에서 픽셀값들을 읽어들이는 반면

텍스쳐는 생성할 때 그래픽 처리 장치의 메모리에 저장되므로 속도가 더 빠르다.

또한 텍스쳐를 그릴 때 확대/축소와 위치 지정 자유롭게 할 수 있다.



먼저 테스트용으로 쓸 이미지 배열을 만든다.

여기서는 텍스쳐 포멧으로 RGBA_8888를 사용할 것인데,

Red, Green, Blue, Alpha(불투명도)에 해당하는 정보들을 각각 8비트(1바이트)씩 사용하는 방법이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
int w = 100;
int h = 100;
GLubyte map[100*100*4];
int i,j;
for(i=0; i<h; i++) {
    for(j=0; j<w; j++) { 
        map[w*i*4+j*4+0= 0x99; //Red
        map[w*i*4+j*4+1= 0x99; //Green
        map[w*i*4+j*4+2= 0xCC; //Blue
        map[w*i*4+j*4+3= 0xAA; //Alpha
    }
}
 

cs


100x100 크기의 0x9999CCAA색 사각형을 나타내는 1차원 배열이 생성된다.

(그릴 때는 2차원으로 처리된다.)





알파 채널을 사용하기 위해 GL_BLEND를 활성화하고,

텍스쳐id로 텍스쳐를 생성한 뒤 glBindTexture()로 텍스쳐id와 텍스쳐라이징 대상을 연결한다.


그리고 glTexImage2D()로 텍스쳐로 쓸 GLubyte 배열을 쓴다.


glTexParameteri()로 확대/축소시 텍스쳐 필터를 설정하고

glTexEnvi()로 텍스쳐 환경 설정을 한다.(레퍼런스 참고)

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);


glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    w, h, 0,
    GL_RGBA, GL_UNSIGNED_BYTE,
    map
);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 


텍스쳐의 너비와 높이가 각각 2의 거듭제곱 꼴일 때 높은 성능을 얻을 수 있다.

(메모리에 2의 거듭제곱 단위로 할당되기 때문에..)

OpenGL ES에서는 아예 2의 거듭제곱꼴만 하용하고 있다.

예시) 64x128, 128x128, 256x64 등







이제 텍스쳐를 그리는 부분이다.

여기서는 평면상에 텍스쳐를 그릴 것인데, 먼저 OpenGL의 좌표계에 대해 알아야 한다.


별도의 설정을 하지 않을 시, 화면의 중앙이 원점이 되며 우측 상단으로 갈 수록 x와 y 값이 각각 증가한다.

우측 상단 꼭지점의 좌표는 (1, 1)이다.


텍스쳐 이미지 자체의 좌표는, 이미지의 좌측하단이 원점이며,

이미지의 우측상단이 (1, 1)이다.




glOrtho()함수를 쓰면 좌표계(클리핑 범위)를 재설정할 수 있다. 형식은 아래와 같다.

glOrtho(왼쪽, 오른쪽, 아래, 위, z축 근거리방향, z축 원거리방향)


2D만 고려할 때, glOrtho(0, 너비, 높이, 0 정도로 지정하면

MFC, JS 등에서처럼 좌측상단을 원점으로 쓸 수 있다.


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glOrtho(0, 창의 너비, 창의 높이, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glBindTexture(GL_TEXTURE_2D, texId);

glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
    glTexCoord2f(1.0, 0.0); glVertex2f(w, 0);
    glTexCoord2f(1.0, 1.0); glVertex2f(w, h);
    glTexCoord2f(0.0, 1.0); glVertex2f(0, h);
glEnd();
 



glTexCoord2f()로 그릴 텍스쳐 영역을 지정할 때

텍스쳐가 뒤집혀 있는 상태이므로 아래와 같은 순서로 그린 것이다.




아래는 png 이미지를 로드하여 화면에 두 번 표시해본 화면이다.

이미지를 로드하기 위해 SDL2를 사용했는데, SDL2 대신 glut과 pnglib라이브러리 써도 png 이미지파일을 읽어올 수 있다. (pnglib라이브러리 없이도 BMP파일은 로드 가능.)



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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#pragma comment (lib,"SDL2")
#pragma comment (lib,"SDL2main")
#pragma comment (lib,"SDL2_image")
#pragma comment (lib,"opengl32.lib")
 
#include <cstdio>
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
 
using namespace std;
 
 
SDL_Renderer *renderer;
 
 
int main(int argc, char **argv){
    int winWidth = 800;
    int winHeight = 600;
 
    SDL_Window *win = NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Surface *image;
    SDL_RWops *rwop;
    rwop = SDL_RWFromFile("../res/img.png""rb");
    image = IMG_LoadPNG_RW(rwop);
    GLubyte *map = (GLubyte*)image->pixels;
 
    int w, h; 
    w = image->w;
    h = image->h;
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
        return 1;
 
    win = SDL_CreateWindow("gl"100100, winWidth, winHeight, SDL_WINDOW_OPENGL);
    renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
 
    SDL_GLContext context;
    context = SDL_GL_CreateContext(win);
 
    
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);
 
    GLuint texId;
    glGenTextures(1, &texId);
    glBindTexture(GL_TEXTURE_2D, texId);
    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGBA,
        w, h, 0,
        GL_RGBA, GL_UNSIGNED_BYTE,
        map
    );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
 
    while (1) {
        SDL_Event e;
        if (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT)
                break;
            else if (e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE)
                break;
        }
        
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glOrtho(0, winWidth, winHeight, 0-11);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        
        glBindTexture(GL_TEXTURE_2D, texId);
 
        glBegin(GL_QUADS);
            glTexCoord2f(0.00.0); glVertex2f(00);
            glTexCoord2f(1.00.0); glVertex2f(w, 0);
            glTexCoord2f(1.01.0); glVertex2f(w, h);
            glTexCoord2f(0.01.0); glVertex2f(0, h);
        glEnd();
 
        glBegin(GL_QUADS);
            glTexCoord2f(0.00.0); glVertex2f(0+300+30);
            glTexCoord2f(1.00.0); glVertex2f(w+300+30);
            glTexCoord2f(1.01.0); glVertex2f(w+30, h+30);
            glTexCoord2f(0.01.0); glVertex2f(0+30, h+30);
        glEnd();
 
        
        SDL_GL_SwapWindow(win);
        SDL_Delay(21);
 
    }
 
    SDL_GL_DeleteContext(context);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(win);
 
    return 0;
 
}
 
 
cs













VS2013에서 SDL2와 SDL_Image, openGL을 사용하기 위해

개발환경을 설정하는 단계를 포스팅해봅니다.




1 .SDL 홈페이지(https://www.libsdl.org)에서 SDL2 다운로드 페이지로 들어간다.

2. Windows용Development Libraries zip 파일을 다운받아서 압축을 푼다

3. 비주얼스튜디오를 열고 win32 콘솔 프로그램 프로젝트를 만든다.

4. 프로젝트 속성 창을 열고 Configuration Properties의 VC++ Directories로 들어간다.




5. Include Directories 항목에는 SDL2의 헤더파일(.h)이 있는 폴더를 지정하고,

   Library Directories 항목에는 SDL2의 lib파일이 있는 폴더를 지정한다.

  여기서 32비트와 64비트가 있는데 32비트로 진행하였다.


6. 이제 링커 설정에서 라이브러리 의존성을 지정해야 한다.

  5번과 같은 속성창에서 Linker - Input - Additional Dependencies에

라이브러리 파일의 이름을 추가해도 되지만 여기서는 소스코드에 직접 넣었다.

1
2
3
4
5
6
7
8
9
#pragma comment (lib,"SDL2")
#pragma comment (lib,"SDL2main")
 
#include <SDL.h>

cs

소스코드의 윗부분에 #pragma comment로 lib파일을 쓰면 된다.

SDL2.lib과 SDL2main.lib을 추가한다.



경우에 따라 라이브러리파일의 이름이 SDL2.lib이 아니라 SDL.lib일 수도 있으니 주의.





7. 이제 SDL의 이미지파일 처리 등을 도와주는 SDL_Image 라이브러리를 설치한다.

 https://www.libsdl.org/projects/SDL_image/에서

2번과 같이 Development Libraries zip파일을 받는다.

5번에서처럼 Include Directories와 Library Directories를 각각 추가한다.

*다른 SDL 관련 추가 라이브러리도 이와 같은 방법으로 추가하면 된다.





8. 사용할 라이브러리와 헤더파일들을 소스코드에 명시한다.

opengl함수들을 직접 사용하기 위해서는 opengl32.lib 파일을 링크해야 한다.

1
2
3
4
5
6
7
8
9
#pragma comment (lib,"SDL2")
#pragma comment (lib,"SDL2main")
#pragma comment (lib,"SDL2_image")
#pragma comment (lib,"opengl32.lib")
 

#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
cs




※ 실행시 SDL.dll을 찾을 수 없다는 오류가 난다면

다운받은 라이브러리 폴더에 있는 SDL2.dll과 SDL2_image.dll을 복사하여

프로젝트 폴더 내의 Debug 혹은 Release폴더에 넣는다.




아래는 간단하게 작성해본 테스트용 코드..

프로젝트 디렉토리에 res 라는 폴더가 있고

그 폴더에 있는 img.png 파일(512x512)을 로드하여 화면에 표시한다.


(SDL의 함수들만 사용해도 이미지를 띄울 수 있지만

opengl함수들을 사용해보기 위해 아래와 같이 작성하였습니다.)


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#pragma comment (lib,"SDL2")
#pragma comment (lib,"SDL2main")
#pragma comment (lib,"SDL2_image")
#pragma comment (lib,"opengl32.lib")
 
#include <cstdio>
#include <SDL.h>
#include <SDL_opengl.h>
#include <SDL_image.h>
 
using namespace std;
 
int main(int argc, char **argv){
 
    SDL_Window *win = NULL;
    SDL_Surface *image;
    SDL_RWops *rwop;
    rwop = SDL_RWFromFile("../res/img.png""rb");
    image = IMG_LoadPNG_RW(rwop);
    GLubyte *map = (GLubyte*)image->pixels;
 
    //Initialize SDL.
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
        return 1;
 
    //Create the window
    win = SDL_CreateWindow("SDL_GL"100100400300, SDL_WINDOW_OPENGL);
 
    SDL_GLContext context;
    context = SDL_GL_CreateContext(win);
 
    glEnable(GL_TEXTURE_2D);
    GLuint texId;
    glGenTextures(1, &texId);
    glBindTexture(GL_TEXTURE_2D, texId);
    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGBA,
        5125120,
        GL_RGBA, GL_UNSIGNED_BYTE,
        map
    );
    
    // Texture filter
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
    // main loop
    while (1) {
 
        //event handling
        SDL_Event e;
        if (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT)
                break;
        }
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
        glBindTexture(GL_TEXTURE_2D, texId);
        glBegin(GL_QUADS);
        glTexCoord2f(0.00.0); glVertex2f(-0.71.0);
        glTexCoord2f(1.00.0); glVertex2f(0.71.0);
        glTexCoord2f(1.01.0); glVertex2f(0.7-1.0);
        glTexCoord2f(0.01.0); glVertex2f(-0.7-1.0);
        glEnd();
 
        SDL_GL_SwapWindow(win);
        SDL_Delay(16);
 
    }
 
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(win);
SDL_Quit();
    return 0;
 
}
 
 
cs




실행결과








자세한 코드 내용은 다음 포스트에 계속돱니다

http://tibyte.kr/232







한글로 주석을 작성하고  javac로 컴파일할 때 인코딩 문제 때문에

다음과 같은 에러 메시지를 볼 수 있다.


unmappable character for encodig MS949


해결방법 : javac의 기본 인코딩 설정을 ms949에서 utf-8로 바꿔주면 된다.


예시 : javac Project1.java -encoding UTF-8








'ㄱ-힣'과 한글만 입력받게 하기


한글만 허용하도록(혹은 한글만 제한하는) 문자열을 검사할 때

ㄱ-힣 이라고 범위를 지정하는 경우를 볼 수 있는데

ㄱ는 유니코드 코드포인트가 12593,  '가'는 44032로 상당히 멀리 떨어져 있기 때문에

그 사이에 있는 문자들도 포함하게 되어버린다.


만약 다음과 같은 코드로 한글만 허용토록 했다면(Java),

if(str.matches("^[ㄱ-힣]*$"))

유니코드에서 코드포인트가 저 범위 안에 들어 있는 '誤'같은 문자까지 입력이 가능하게 된다.





따라서 자음/모음만 낱으로 있는 부분과 가-힣 부분을 따로 써야 한다.

 ^[ㄱ-ㅎㅏ-ㅣ가-힣]*$

혹은 완전한 글자만 허용하려면

 ^[가-힣]*$

으로 정규식을 쓰면 된다.



UTF-8과의 인코딩 문제 등으로 안 될 경우에는,

^[\u3131-\u318E\uAC00-\uD7A3]*$

(ㄱ-ㆎ 가-힣)

(ㆎ는 아래애)



\u1100-\u11f9 범위의 조합형 자모도 있지만 이 포스팅에서는 생략.






※사용예시 (프로그래밍 언어에 따라 정규식을 /와 /로 묶어서 표현하는 경우가 있음)


*Java


*AS3.0





결론은 ㄱ-힣 범위를 쓰면 의도와 다른 결과가 나올 수 있다는 것입니다..




1페이지부터 5페이지까지 5개의 장면이 있고

다음 버튼과 이전 버튼이 있어서 페이지를 넘길 수 있는 프로그램을 만드는데

if문을 쓰지 않고 모듈러연산으로 처리하는 것이 생각나서 식을 구해보기로 했다.


아래 그림은 1부터 n까지의 자연수가 있을때

아무것도 더하지 않고 mod n연산을 하여 +1을 한 결과와,

처음에 1을 더한 경우, 2를 더한 경우에 대한 내용이다.


아래 그림은 처음에 n-2을 더한 경우와, n-1을 더한 경우이다. 

예를 들어 자연수의 집합 {1, 2, 3, 4, 5} 가 있을 때

집합의 각 원소에 n-2인 3을 더하면  집합은{4, 5, 6, 7, 8}가 되고 

이 집합의 mod 5를 구하면 {4, 0, 1, 2, 3} 이 되어

다시 이 집합에 +1을 하면 {5, 1, 2, 3, 4}가 되어서

최종적으로는 원래 집합이 우측으로 1칸씩 순환 이동하였다고 볼 수 있다.

또한 2는 1이 되고, 3은 2가 되고, 4는 3이 되고, 5는 4가 되고, 1은 다시 5가 되었으므로

처음에 만들고자 하였던 프로그램의 이전 버튼에 사용할 수 있을 것이다.


다시 위의 두 그림을 자세히 살펴보면,

집합의 원소 a가 있고 집합의 원소가 n개인 경우에, 이 집합의 원소를 p씩 증가시키고 싶을 때

(예를 들어 각각의 1,2,3,4,5 페이지에서 다음버튼을 눌러서 각각 2,3,4,5,1 페이지를 만들고자 하는 경우 등) 

다음과 같은 함수를 얻을 수 있다.

f(a,p,n) = (a+(p-1))% n +1

여기서 p는 좌측으로 p칸 순환시프트시킬 값도 된다.


처음의 프로그램 문제로 되돌아가서

5페이지일때의 다음버튼을 만든다고 하면 아래와 같이 프로그램을 작성할 수 있을 것이다.

page = (currentPage+(1-1))%5 + 1;

필요없는 연산을 제거하면,

page = currentPage%5 + 1;


이번에는 2페이지씩 넘기는 버튼을 만든다고 하면 코드는,

page = (currentPage+(2-1))%5 + 1; 에서 역시 필요없는 부분을 제거하여
page = (currentPage+1)%5 + 1;
이 된다.

그러면 반대방향으로 1페이지를 넘기는 이전버튼에 들어갈 코드는 어떻게 될까?
순환 시프트이므로 p값을 넣을 자리에 n-p값을 놓으면 된다.
page = (currentPage+(5-1-1))%5 + 1; 
page = (currentPage+3)%5 + 1; 


정리 :
(a+(p-1))% n +1
→ p씩 순환증가
→ p씩 좌측 순환시프트 

(a+(n-p-1))% n +1
→ p씩 순환감소
→ p씩 우측 순환시프트 



================================================================================





일전에 덧셈과 뺄셈으로 두 변수의 값을 바꾸는 것을 올렸었다.(http://www.tibyte.kr/95)

이 방법은 연산과정에서 데이터형의 비트수를 넘어가면 오버플로우가 발생할 수 있는데,

다음과 같이 비트XOR(배타적논리합)연산을 쓰면 오버플로가 일어날 일이 없다.


a = a^b;

b = a^b;

a = a^b;


//한 줄로 쓰면

a ^= b ^= a^= b;


배타적 논리합 연산이므로 1행에서 a와 b의 각 자리의 비트열 차이(같은지 다른지)에 대한 정보가 a에 할당된다.

2행에서 b 우측의 항은 결과적으로 a^b^b 연산이 되어 a값이 들어간다.

3행이 처리될 때 a는 a^b 이고 b는 초기의a값이므로 a^b^a가 되어 b값이 들어가게 된다.

이렇게 a와 b의 값이 서로 바뀌게(swap) 되는 것이다.



==========================




 

isometirc 쿼터뷰의 타일을 만들 때 64x32크기의 타일을 그냥 이어붙여 버리면

타일의 가장자리가 짤리는 현상이 발생한다.

경계선을 원래크기로 보면 가느다란 선으로 보일 뿐이지만 실제로는 픽셀로 맞물려 있기 때문이다.

아래그림처럼 경계선(테두리)의 굵기가 1이면 해당 경계선을 어느 타일이 덮어야할지 모호해진다






그래서 타일의 경계에 있는 픽셀(외곽 픽셀)들이 겹치게 하면 안되는데, 

타일이 차지하는 영역이 짝수x짝수이면 대각선 사이에 넣어야 할 타일이

꼭 들어맞지 않게 된다. (하단의 선이 직선이 되지 않고 엇갈려 있다)





그렇기 때문에 타일하나의 크기가 홀수x짝수나 짝수x홀수의 형태가 되어야 하는데

여기서는 너비가 높이보다 길기 때문에 높이는 그대로 두고 너비를 한 픽셀 줄여서 홀수로 만든다.

(그림은 32x16타일의 픽셀들을 나타낸 것으로 오른쪽 세로 한줄이 비어있는것을 볼 수 있다.)




이렇게 해서 타일을 붙이면 네 타일이 만나는 부분이 아래 그림과 같이 된다.







이제 타일들을 맞물리게 배치했다.

비록 실제 타일크기는 31x16이지만, 각 타일들의 좌표 기준점들은

(0,0), (32,0), (16,0), (32,16), (16,8) 등으로 프로그램에서 처리하기 쉽게 딱딱 떨어진다.






타일하나당 픽셀을 채워 넣는 다른 방법도 있는데,

타일들이 서로 겹치지 않고 꼭 들어맞는지,

배치한 타일의 좌표값이 타일크기에 맞게 결정되는지,  

타일들의 경계선이 엇갈려 있지 않고 직선이 되는지를 만족해야 할 것이다.










+ Recent posts