그래픽 좌표계
- 작성자
- 고친과정
2010년 3월 20일 : 처음씀
1.1. 좌표계의 종류
- 하나의 점은 16K color 수를 표현할수 있다고 가정합니다.
- 흰색(White) 부분이 실제 모니터에 표시되는 점이며 검은색이 비 가시영역으로 볼수 있습니다. 모니터를 자세히 들여다 보세요. 점의 집합으로 표현되는 이러한 화면에서 좌표계의 선택은 매우 중요한 요소입니다.
- 파란색(Blue) 사각형 하나는 실제 화면에 표시되는 점을 기준으로 하는 좌표계를 가정합니다. (Pixel 좌표계)
- 초록색(Green) 사각형은 실제 화면에 보이지 않는 비가시영역을 기준으로 하는 좌표계를 가정합니다. ( Bound 좌표계: 이 영역은 Paging unit의 효율을 위해서 하나의 Row당 Padding되는 영역으로 설명될수 있습니다. )
- 이와 같이 실제 표시되는 점을 기준으로 하는 좌표표현 방법(Pixel 좌표계)과 표시되는 점의 외곽의 비가시영역을 기준으로 하는 좌표표현 방법(Bound 좌표계)이 존재합니다. 어느것이 더 좋다고 하는 것 보다는 자신의 그래픽 구현이 어느것에 더 유리한지 고민후에 좌표계를 결정하는 개발자의 판단 몫이라고 할수 있겠습니다.
1.2. Pixel 좌표계
실제 화면에 표시되는 점을 하나의 단위로 보는 좌표계입니다.
위에서 화면전체는 Pixel좌표계로는 다음과 같이 표시될수 있습니다.
위의 그림에서 붉은색 사각형은 다음과 같이 표현될수 있습니다.
또 다른 표현으로는 다음과 같이도 표현합니다.
만약 hwport_region_t 를 hwport_rectangle_t 로 변환하려면 다음과 같은 공식이 성립합니다.
반대로 hwport_rectangle_t 를 hwport_region_t 로 변환하려면 다음과 같은 공식이 성립합니다.
위에서 화면전체는 Pixel좌표계로는 다음과 같이 표시될수 있습니다.
typedef struct hwport_rectangle_ts { int x, y; unsigned int width, height; }__hwport_rectangle_t; #define hwport_rectangle_t __hwport_rectangle_t typedef struct hwport_screen_ts { int bits_per_pixel; size_t bytes_per_line; hwport_rectangle_t rectangle; }__hwport_screen_t; #define hwport_screen_t __hwport_screen_t static hwport_screen_t my_screen = { 16, /* bits_per_pixel = <위 그림에서 하나의 점은 16K 의 Color수를 표현한다고 가정하면 하나의 점을 표현하는데는 16bits가 필요합니다.> */ (size_t)((32u + 4u) * (16u / 8u)), /* bytes_per_line = 가시영역인 32개의 가로 Pixel수와 비가시영역 4개의 Pixel을 더하고 bits_per_pixel을 bytes_per_pixel로 곱한것입니다. */ { 0, 0, 32u, 32u } /* rectangle = 비가시영역을 제외한 부분을 뜻합니다. 여기서 x, y는 항상 0이라고 할수는 없고 Over scan등이 고려될때는 0이 아닐수 있습니다. */ };
위의 그림에서 붉은색 사각형은 다음과 같이 표현될수 있습니다.
hwport_rectangle_t my_rectangle = { 2, 2, 9u, 9u };
또 다른 표현으로는 다음과 같이도 표현합니다.
typedef struct hwport_region_ts { int x1, y1, x2, y2; }__hwport_region_t; #define hwport_region_t __hwport_region_t hwport_region_t my_region = { 2, 2, 10, 10 };
만약 hwport_region_t 를 hwport_rectangle_t 로 변환하려면 다음과 같은 공식이 성립합니다.
#define MIN(m_left,m_right) ((m_left < m_right) ? (m_left) : (m_right)) #define MAX(m_left,m_right) ((m_left > m_right) ? (m_left) : (m_right)) my_rectangle.x = MIN(my_region.x1, my_region.x2); my_rectangle.y = MIN(my_region.y1, my_region.y2); my_rectangle.width = (unsigned int)( MAX(my_region.x1, my_region.x2) - MIN(my_region.x1, my_region.x2) + 1 ); my_rectangle.height = (unsigned int)( MAX(my_region.y1, my_region.y2) - MIN(my_region.y1, my_region.y2) + 1 );
반대로 hwport_rectangle_t 를 hwport_region_t 로 변환하려면 다음과 같은 공식이 성립합니다.
if((my_rectangle.width <= 0u) || (my_rectangle.height <= 0u)) { /* ERROR: invalid width or height */ } my_region.x1 = my_rectangle.x; my_region.y1 = my_rectangle.y; my_region.x2 = ((int)my_rectangle.width) - my_rectangle.x - 1; my_region.y2 = ((int)my_rectangle.height) - my_rectangle.y - 1;
1.3. Bound(Screen) 좌표계
하나의 점 마저도 크게 확대해보면 사각형 또는 어느 범위안의 구역이라는 시점으로 바라본 좌표계로써 보이는 점들의 외곽영역을 기준으로 하는 좌표계
위의 그림에서 붉은색 사각형은 다음과 같이 표현될수 있습니다.
typedef struct hwport_bound_ts { int left, top, right, bottom; }__hwport_bound_t; #define hwport_bound_t __hwport_bound_t typedef struct hwport_screen_ts { int bits_per_pixel; size_t bytes_per_line; hwport_bound_t bound; }__hwport_screen_t; #define hwport_screen_t __hwport_screen_t static hwport_screen_t my_screen = { 16, /* bits_per_pixel */ (32 + 4) * (16 / 8), /* bytes_per_line */ { 0, 0, 32, 32 } /* bound */ };
위의 그림에서 붉은색 사각형은 다음과 같이 표현될수 있습니다.
hwport_bound_t my_bound = { 2, 2, 11, 11 };
1.4. Pixel 좌표계와 Bound 좌표계의 분석
hwport_bound_t를 hwport_rectangle_t 로 변환하려면 다음과 같은 공식이 성립합니다. hwport_region_t를 hwport_rectangle_t 로 변환할때는 1을 더해주어야 했다는 점이 주목해야 될 부분입니다.
my_rectangle.x = my_bound.left; my_rectangle.y = my_bound.top; my_rectangle.width = (unsigned int)(my_bound.right - my_bound.left); my_rectangle.height = (unsigned int)(my_bound.bottom - my_bound.top);
1.5. 2개의 window(Pixel 좌표계 기준) 가 겹치는 영역을 계산하는 예제
이 예제는 2개의 Window 사각 영역에 대하여 겹쳐지는 영역과 겹쳐지지 않는 영역을 계산하는 예제입니다. 보통 Windows Manager 개발에 필요한 요소로 볼 수 있으며 겹쳐지지 않는 영역은 완벽하게 식별하기 위해서는 4개의 영역으로 나뉘어 다룰수 있습니다. 실제 이 연산을 기반으로 Windows Manager를 개발하게 되면 재귀적 연산부가 심도있게 다루어져야 하는데 통상 재귀적 Stack 이용률이 매우 크기 때문에 재귀적인 부분을 비 재귀적 연산으로 개발하는 고려가 되어야 바람직합니다.
/* ************************ *[deal] | * * (0) | * * | * *------********** * * *[other] * (1) * * * * * * *Overlap * * * (3) * * * * * * * * **********------* * | * * | (2) * * | * ************************ */ #if !defined(hwport_rectangle_t) # pragma pack(push,8) typedef struct hwport_rectangle_ts { int m_x; int m_y; unsigned int m_w; unsigned int m_h; }__hwport_rectangle_t; # pragma pack(pop) # define hwport_rectangle_t __hwport_rectangle_t #endif int hwport_sep_overlap_window(const hwport_rectangle_t *s_deal_region, const hwport_rectangle_t *s_other_region, hwport_rectangle_t *s_overlap_region, hwport_rectangle_t *s_no_overlap_region /* array[4] */) { int s_temp1; int s_temp2; hwport_rectangle_t s_temp_window; if(hwport_unlikely((s_deal_region == ((hwport_rectangle_t *)0)) || (s_other_region == ((hwport_rectangle_t *)0)))) { return(-1); } /* wide region select to s_temp_window */ s_temp_window.m_x = (s_deal_region->m_x <= s_other_region->m_x) ? s_deal_region->m_x : s_other_region->m_x; s_temp_window.m_y = (s_deal_region->m_y <= s_other_region->m_y) ? s_deal_region->m_y : s_other_region->m_y; s_temp1 = s_deal_region->m_x + ((int)s_deal_region->m_w); s_temp2 = s_other_region->m_x + ((int)s_other_region->m_w); if(s_temp2 > s_temp1) { s_temp1 = s_temp2; } s_temp_window.m_w = (unsigned int)(s_temp1 - s_temp_window.m_x); s_temp1 = s_deal_region->m_y + ((int)s_deal_region->m_h); s_temp2 = s_other_region->m_y + ((int)s_other_region->m_h); if(s_temp2 > s_temp1) { s_temp1 = s_temp2; } s_temp_window.m_h = (unsigned int)(s_temp1 - s_temp_window.m_y); if(((s_deal_region->m_w + s_other_region->m_w) <= s_temp_window.m_w) || ((s_deal_region->m_h + s_other_region->m_h) <= s_temp_window.m_h)) { /* no overlap */ return(0); } if(s_overlap_region == ((hwport_rectangle_t *)0)) { s_overlap_region = (hwport_rectangle_t *)(&s_temp_window); } /* overlap region select */ s_overlap_region->m_x = (s_deal_region->m_x >= s_other_region->m_x) ? s_deal_region->m_x : s_other_region->m_x; s_overlap_region->m_y = (s_deal_region->m_y >= s_other_region->m_y) ? s_deal_region->m_y : s_other_region->m_y; s_overlap_region->m_w = s_deal_region->m_w + s_other_region->m_w - s_temp_window.m_w; s_overlap_region->m_h = s_deal_region->m_h + s_other_region->m_h - s_temp_window.m_h; /* no overlap region select */ if(s_no_overlap_region != ((hwport_rectangle_t *)0)) { s_no_overlap_region[0].m_x = s_deal_region->m_x; s_no_overlap_region[0].m_y = s_deal_region->m_y; s_no_overlap_region[0].m_w = (unsigned int)(s_overlap_region->m_x + ((int)s_overlap_region->m_w) - s_deal_region->m_x); s_no_overlap_region[0].m_h = (unsigned int)(s_overlap_region->m_y - s_deal_region->m_y); s_no_overlap_region[1].m_x = s_overlap_region->m_x + ((int)s_overlap_region->m_w); s_no_overlap_region[1].m_y = s_deal_region->m_y; s_no_overlap_region[1].m_w = (unsigned int)((s_deal_region->m_x + ((int)s_deal_region->m_w)) - (s_overlap_region->m_x + ((int)s_overlap_region->m_w))); s_no_overlap_region[1].m_h = (unsigned int)((s_overlap_region->m_y + ((int)s_overlap_region->m_h)) - s_deal_region->m_y); s_no_overlap_region[2].m_x = s_overlap_region->m_x; s_no_overlap_region[2].m_y = s_overlap_region->m_y + ((int)s_overlap_region->m_h); s_no_overlap_region[2].m_w = (unsigned int)(((int)s_deal_region->m_w) - (s_overlap_region->m_x - s_deal_region->m_x)); s_no_overlap_region[2].m_h = (unsigned int)((s_deal_region->m_y + ((int)s_deal_region->m_h)) - (s_overlap_region->m_y + ((int)s_overlap_region->m_h))); s_no_overlap_region[3].m_x = s_deal_region->m_x; s_no_overlap_region[3].m_y = s_overlap_region->m_y; s_no_overlap_region[3].m_w = (unsigned int)(s_overlap_region->m_x - s_deal_region->m_x); s_no_overlap_region[3].m_h = (unsigned int)(((int)s_deal_region->m_h) - (s_overlap_region->m_y - s_deal_region->m_y)); } return(1); }
1.6. 예제소스
- bitblit.tar.gz (1.22 KB) : Text console 상에서 구현하는 간략한 FrameBuffer 에 대한 개념을 이해하기 위한 예제
- fbinfo.tar.gz (1.6 KB) : Linux Frame Buffer 를 이해하기 위한 간략한 FrameBuffer 정보추출 기초 예제
- fbclock.tar.gz (2.81 KB) : Linux Frame Buffer 상에서 시계바늘을 그리는 간략한 예제 (점, 선, 회전각에 대한 이해를 위한...)
- fbfire.tar.gz (2.44 KB) : Linux Frame Buffer 상에서 좀더 가시적인 효과를 어떻게 구현하는지에 대한 예제 (불타오르는 화면효과 연출, 색상을 다루는 예제)
- bitmap.tar.gz (17.46 KB) : Text console 상에서 간략히 글자를 어떻게 Bitmap으로 다루고 이를 Frame Buffer에 도입할수 있는지에 대한 예제
- mz3d.tar.gz (16.39 KB) : Linux frame buffer 상에서 동작하는 3차원를 다루는 예제
- mz3dx_simple.tar.gz (6.27 KB) : X-Windows 상에서 동작하는 3차원을 다루는 예제