[주의] 멍청한 실수임
vbo를 랜더링 하기 전에 다음 함수들을 호출해주자
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
vbo->Render();
나는 바보다
'개발 > SFML' 카테고리의 다른 글
[SFML-랜더링] 무한 루프 스크롤 만들기 (0) | 2014.07.13 |
---|
[주의] 멍청한 실수임
vbo를 랜더링 하기 전에 다음 함수들을 호출해주자
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
vbo->Render();
나는 바보다
[SFML-랜더링] 무한 루프 스크롤 만들기 (0) | 2014.07.13 |
---|
class foo extend Actor {
...
@Override
public void draw(Batch batch, float parentAlpha) {
batch.end();
mPolygonSpriteBatch.setTransformMatrix(batch.getTransformMatrix());
mPolygonSpriteBatch.begin();
sprite.draw(mPolygonSpriteBatch);
mPolygonSpriteBatch.end();
batch.begin();
}
...
}
It is very simple, I suddenly know while I saw the core libgdx source code.
we need transformation matrix to applying it.
and the transformation matrix is automatically generated when we call the mutators
(to rotate, shift, scaling)
for Actors. and it passed by tree like manner.
so, what we have to do is just pick the transformation matrix of Actor (by batch parameter)
and applying it to the batch object whatever we want.
that's all
기본적으로 MS windows 환경에서는 MS949의 한국형 확장인 euc-kr을 사용한다. (우리가 흔히 아는 c의 char 형이 한국 윈도우에서 저 방식이다.)
하지만 자바는 2바이트 캐릭터로 문자열 처리에 무조건 유니코드를 사용하며 인코딩은 UTF-16이라고 생각하고 있었다.
byte[] dub = PACKETLIST.LOGIN.getByteHead(m_LoginName.length() + 1);
outToServer.write(PACKETLIST.LOGIN.getByteHead(m_LoginName.length() + 1));
byte[] fd= m_LoginName.getBytes();
String str = new String(m_LoginName.getBytes("MS949"), "euc-kr");
byte[] fd2= m_LoginName.getBytes("euc-kr");
String str3 = new String(m_LoginName.getBytes("euc-kr"), "UTF-16LE");
byte[] fd3= m_LoginName.getBytes("UTF-16LE");
String hex = byteArrayToHex(m_LoginName.getBytes("UTF-16LE"));
다음과 같은 더러운 실험을 했다.
여차저차해서 알게된것은 자바는 2바이트 캐릭터를 사용하여 유니코드 인코딩을 사용한다고 착각하고 있었지만, 인코딩 방식은 ANSI 표준 + euc-kr의 식이였다. (c의 char 처럼)
wchar_t는 한 변수에 유니코드 글자 하나의 코드를 포함하며, 그는 UTF-16LE와 같은 방식이다. (그냥 uft-8 하면 빅 엔디안이며, 앞 부분에 0xfffe 라는 바이트가 하나 더 붙는다.)
따라서 서버에서 wchar_t의 형식으로 받고 싶다면 ("UTF-16LE")로 변환하고 전송하면 된다.
PostThreadMessage 실패시 (1) | 2014.08.01 |
---|---|
std::thread에서 native thread 핸들 얻기 (0) | 2014.07.17 |
PostThreadMessage(m_dwServerID, TH_CLEAR_PDATA, 0, (LPARAM)this);
로 메시지를 넘겨주고 처리 하려는데, 메시지 객체가 NULL 값을 반환하는 오류가 발생하였다.
오류 메시지를 살펴보니
1159 ERROR_MESSAGE_SYNC_ONLY
였는데, 이는 구 버전에서 사용하던 메시지 ID (#define TH_CLEAR_PDATA 0x9c)가 WM_USER 보다 작은 값을
가지고 있기 때문에, 시스템 메시지 영역과 중복되어 발생한 오류였다.
#define TH_CLEAR_PDATA (WM_USER + 0x9c)
이런식으로 수정하여 해결하였다.
JAVA-MFC 통신시 유니코드 문자열 전송 코드페이지 문제 (0) | 2014.08.07 |
---|---|
std::thread에서 native thread 핸들 얻기 (0) | 2014.07.17 |
회사에서 협업툴로 트렐로를 사용한다길래 게임 만드는데 대한 간단한 이슈들을 모아서 정리해보았다.
비록 내가 혼자서 게임을 만들기 때문에 협업툴로서의 장점은 잘 확인할 수 없었지만 ㅋㅋ
여러개의 카드가 들어가는 리스트와 구분짓는 필터,
팀원들을 간단하게 끌어놓는 구조등은 굉장히 편해보였다.
왜 예제의 함수명이나 변수명은 foo와 bar를 사용할까 (1) | 2014.07.17 |
---|
외국 사이트들에 가보면 보통 임의의 함수나 변수 명으로 foo 혹은 bar를 사용한다.
예시)
01.
// thread example
02.
#include <iostream> // std::cout
03.
#include <thread> // std::thread
04.
05.
void
foo()
06.
{
07.
// do stuff...
08.
}
09.
10.
void
bar(
int
x)
11.
{
12.
// do stuff...
13.
}
14.
15.
int
main()
16.
{
17.
std::
thread
first (foo);
// spawn new thread that calls foo()
18.
std::
thread
second (bar,0);
// spawn new thread that calls bar(0)
19.
20.
std::cout <<
"main, foo and bar now execute concurrently...\n"
;
21.
22.
// synchronize threads:
23.
first.join();
// pauses until first finishes
24.
second.join();
// pauses until second finishes
25.
26.
std::cout <<
"foo and bar completed.\n"
;
27.
28.
return
0;
29.
}
foo와 bar의 기원은 이차 세계대전중 미군의 속어인 FUBAR fuxxed up beyond all recognition (형체도 알아볼 수 없을 정도로 x 되다.)에 있다고 한다.
추상적이고, 별 의미없이 정의할 때 사용되는듯 하다
01.
#include <thread>
02.
#include <mutex>
03.
#include <iostream>
04.
#include <chrono>
05.
#include <cstring>
06.
#include <pthread.h>
07.
08.
std::mutex iomutex;
09.
void
f(
int
num)
10.
{
11.
std::this_thread::sleep_for(std::chrono::seconds(1));
12.
13.
sched_param sch;
14.
int
policy;
15.
pthread_getschedparam(pthread_self(), &policy, &sch);
16.
std::lock_guard<std::mutex> lk(iomutex);
17.
std::cout <<
"Thread "
<< num <<
" is executing at priority "
18.
<< sch.sched_priority <<
'\n'
;
19.
}
20.
21.
int
main()
22.
{
23.
std::
thread
t1(f, 1), t2(f, 2);
24.
25.
sched_param sch;
26.
int
policy;
27.
pthread_getschedparam(t1.native_handle(), &policy, &sch);
28.
sch.sched_priority = 20;
29.
if
(pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) {
30.
std::cout <<
"Failed to setschedparam: "
<< std::
strerror
(
errno
) <<
'\n'
;
31.
}
32.
33.
t1.join(); t2.join();
34.
}
http://en.cppreference.com/w/cpp/thread/thread/native_handle
JAVA-MFC 통신시 유니코드 문자열 전송 코드페이지 문제 (0) | 2014.08.07 |
---|---|
PostThreadMessage 실패시 (1) | 2014.08.01 |
Air friction, or air drag, is an example of fluid friction. Unlike the standard model of surface friction, such friction forces are velocity dependent. The velocity dependence may be very complicated, and only special cases can be treated analytically. At very low speeds for small particles, air resistance is approximately proportional to velocity and can be expressed in the form
where the negative sign implies that it is always directly opposite the velocity. For higher velocites and larger objects the frictional drag is approximately proportional to the square of the velocity:
where ρ is the air density, A the cross-sectional area, and C is a numerical drag coefficient.
Index
Fluid friction HyperPhysics***** Mechanics ***** FluidsGo Back
양력의 발생은 압력의 차이로도 설명이 가능하다. 압력은 단위 면적에 작용하는 변형력을 뜻한다. 유체 속에 놓인 익형에게 전달되는 변형력의 알짜힘은 각 부분마다 다르다. 이 때문에 힘의 편향이 일어나게 되고, 각 부분이 받는 압력 역시 달라지게 된다. 그 결과 익형의 볼록한 부분은 상대적으로 압력이 적은 상태가 되고 오목한 쪽은 압력이 높아져 양력이 발생한다.[11]
1754년 레온하르트 오일러는 뉴턴 운동 법칙의 제2법칙을 응용하여 아래와 같은 압력차 계산 공식을 정리하였다.[12]
무한 루프 스크롤 만들기, 옛날 횡, 종 스크롤링 게임들에서 많이 사용되었던 스롤링링 방식중에 하나이다. 항성계를 시뮬레이트 하고 싶은 내 게임에서는 빠질수가 없는 기능이다.
무한 루프 스크롤링을 하려면 일단 내가 맵을 어떻게 그리는지를 확실히 해둘 필요가 있다.
타일맵을 그려넣는 방식은 여기저기 넘치지만, SFML에서 내가 쓰는 방식은 다음과 같다.
1) 전체 타일맵 정보를 메모리에 모두 저장 (메모리 공간을 아끼기 위해 일부만 저장해야할 필요가 있어 보인다. 다만, 디스크 IO에 의해서 느려지지 않아야한다.)
2) 캐릭터 위치에 따라 필요한(보이는) 타일맵을 렌더 타겟에 블리팅 (성능 저하를 막기 위해서이다.)
3) 뷰포트를 캐릭터 시점 및 확대축소에 따라 따라가면서 이동
이전에 SDL에서는 뷰 포트를 사용하지 않았기 때문에, 화면에서의 캐릭터의 위치는 고정하고 모든 맵 스프라이트들을 순회하면서 블리팅하여 뿌려주는 방식으로, 지금와서 생각해보면 상당이 무식한 방식이라고 생각한다.
뷰포트가 캐릭터를 따라서 가므로 매번 스프라이트 좌표를 캐릭터 위치에 따라 갱신해줄 필요 없이, 그 자리에 그리면 된다.
그러나 뷰포트로 그리는 경우에는 무한 스크롤링시에 각 분할된 스크롤들의 경계선에 대한 문제가 생긴다.
하늘색이 화면, 까만색이 무한 루프를 하지 않는 경우에 표시되지 않는 루프 영역 주황색이 원래 표시되던 본 병역이다. 초록색이 월드맵이다.
경계선 문제를 해결하기 위해서, 뷰포트가 랜더 타겟의 한계 영역을 벗어났을때의 무한 루프를 지원하는가 살펴 봤더니 그런것은 없었다. openGL 영역으로 가면 있을지도 모른다는 생각이 들었지만, 모듈을 수정할 생각을 하니 이내 관두었다.
그래서 간단하게 생각해 봤다. 렌더링 함수의 길이가 길어지는 것은 정말 사양하지만, 개발의 편의를 위해서 랜더링 함수 중간에 랜더링 영역 체크 부분을 음수 혹은 월드맵 바깥 영역까지 확장하고, 확장된 경우에 모듈러 연산을 통해서 그 부분에 그려져야할 타일을 얻어낸다.
그런후 렌더링 직전에 바깥 렌더링 영역의 좌표 공간으로 타일을 치환한 뒤에, 원상복구 시켜놓는다.
무지막지하게 무식한 방법이지만, 다른수가 마땅히 떠오르지 않아 일단 이렇게 해두었다.
그런데 이렇게 해두고 나니 여러가지 문제가 발생했다.
1) 좌우영역의 루프는 정상적으로 동작하지만, 상하 영역의 루프는 캐릭터 좌표에 따라 루프후 빈 공간이 생기는 문제가 생겼다.
[openGL] glDrawElements가 안될때 (0) | 2016.09.30 |
---|
[SDL 게임 개발 프로그래밍 튜터]
1. SDL의 시작(2) - 코드분석
지난 시간에는 기본적인 개발환경 설정과 개발 환경 테스트를 해보았습니다. 오늘은 지난 시간에 실습한 코드를 바탕으로 SDL에서 필수적인 몇가지 객체와 함수들에 대해서 알아봅시다.
1. 코드
우선 코드를 위에서부터 차례대로 보자면,
01.
//SDL과 표준 입출력을 사용합니다.
02.
#include < sdl.h >
03.
#include < stdio.h >
04.
05.
//스크린 너비높이 설정
06.
const
int
SCREEN_WIDTH = 640;
07.
const
int
SCREEN_HEIGHT = 480;
08.
09.
//우리가 랜더링할 윈도우
10.
SDL_Window* gWindow = NULL;
11.
12.
//윈도우가 소유하고 있는 서페이스
13.
SDL_Surface* gScreenSurface = NULL;
14.
15.
//스크린 위에 로드되어 표시되어질 이미지 서페이스
16.
SDL_Surface* gHelloWorld = NULL;
우선 #include로 헤더를 추가해서 SDL 함수들의 원형을 컴파일러가 알게 합시다. 그리고 상수를 두개 만들어 우리가 세팅할 스크린의 크기를 미리 정의해둡시다.
그리고 전역 변수들을 선언해서 사용할 Surface와 Window를 선언해줍니다.
위의 그림은 Surface와 Window에 대해서 말하고 있습니다. 프로그냄 내에서 가상 표면 (Surface)들을 만들어서 내부적 연산 (충돌이나 화면 효과등) 수행합니다. 그 다음 생성된 최종 Surface를 화면에 실제로 보이는 Window에 Bliting( 비트 블록 단위의 데이터 전송을 의미합니다. 간단히 화면에 뿌려준다고 표현하겠습니다. )하여 실제 모니터 화면에 나타내게 되는 것입니다.
gWindow 변수는 우리가 실제로 보게될 화면상의 윈도우를 의미합니다. 두개 이상이 될수도 있고, 주 시스템이 SDL이 아닌 (opengl 내부 윈도우에서 SDL 호출)등의 상황에도 사용될 수 있습니다.
gScreenSurface 변수는 그 화면에 표시되고 있는 윈도우의 표면 정보를 가지고 있는 일종의 버퍼(buffer)라고 할 수 있습니다. 버퍼는 성능상의 이유로 게임 프로그래밍의 많은 영역에 걸쳐서 사용되고 있습니다.
gHelloWorld 위의 gScreenSurface 표면에 뿌려져야할 단일 그림 표면입니다. 수지양의 사진이 메모리로 불러와져서 해당 변수안에 저장되어있겠지요.
다음은 bool Init() 함수를 살펴봅시다.
01.
//윈도우를 만들고 SDL을 초기화한다.
02.
bool
init()
03.
{
04.
//SDL 초기화
05.
if
( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
06.
printf
(
"SDL could not initialize! SDL_Error: %s\n"
, SDL_GetError() );
07.
return
false
;
08.
}
09.
else
{
10.
//윈도우 생성
11.
gWindow = SDL_CreateWindow(
"SDL Tutor"
, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
12.
if
( gWindow == NULL ) {
13.
printf
(
"Window could not be created! SDL_Error: %s\n"
, SDL_GetError() );
14.
return
false
;
15.
}
16.
else
{
17.
//윈도우 표면을 가지고 온다.
18.
gScreenSurface = SDL_GetWindowSurface( gWindow );
19.
}
20.
}
21.
return
true
;
22.
}
윈도우를 생성하고 SDL subsystem을 초기화 하는 함수입니다. 모든 초기화가 성공하면 true 아니면 false를 반환합니다.
처음으로 만나는 함수는 SDL_Init입니다.
int SDL_Init(Uint32 flags);
파라매터에 있는 flags에 따라서 하드웨어를 준비하고 SDL 하위 체계를 사용가능하도록 초기화해줍니다. 초기화에 실패할 경우에 0보다 작은 값이 반환됩니다. SDL의 다른 모든 함수들은 이 함수 다음부터 동작 할 수 있습니다.
32비트짜리 flags에는 각 비트에 1이 있는가 0이 있는가로 각종 기기에 대한 초기화 여부를 건네받습니다. 하지만 우리는 비트연산 걱정 할 필요 없이 간단히 정의된 SDL_INIT_EVERYTHING으로 초기화 해줍시다. (예제 코드에서는 비디오 장치만 사용하기 때문에 SDL_INIT_VIDEO를 flag로 주었습니다. || or 연산을 이용해서 여러개의 flag를 골라서 사용할 수 있습니다. flag에 대한 자세한 내용은 SDL.h를 참고하거나 http://wiki.libsdl.org)를 참고하세요.)
다음 함수는 SDL_CreatWindow입니다.
SDL_Window * SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags);
title의 이름을 가진 윈도우를 생성합니다. 윈도우의 왼쪽 위 위치는 x, y로 설정 가능하며 너비와 높이는 w,h로 설정 가능합니다.
flags에서는 풀스크린 여부, 마우스 포커스를 가져가는지의 여부등 윈도우에 관련한 설정 사항을 지정합니다. 우리는 여기서 간단히 윈도우를 보이게 하라는 SDL_WINDOW_SHOWN flag하나만 사용해줍니다.
마지막으로 SDL_getWindowSurface 함수로 현재 윈도우에 대한 표면정보를 가지고 와서 gScreenSurface 변수에 저장해 줍시다.
SDL_Surface * SDL_GetWindowSurface(SDL_Window * window);
특정 윈도우에 대한 표면정보를 가지고 옵니다.
01.
//리소스를 로드
02.
bool
loadMedia()
03.
{
04.
05.
//이미지를 불러온다.
06.
gHelloWorld = SDL_LoadBMP(
"resource\\character.bmp"
);
07.
if
( gHelloWorld == NULL )
08.
{
09.
printf
(
"Unable to load image %s! SDL Error: %s\n"
,
"02_getting_an_image_on_the_screen/hello_world.bmp"
, SDL_GetError() );
10.
return
false
;
11.
}
12.
13.
return
true
;
14.
}
프로그램에서 사용할 이미지를 메모리로 불러오는 함수입니다.
#define SDL_LoadBMP(filename)
SDL_LoadBMP는 BMP파일을 메모리 표면에 불러오는 매크로함수입니다. 실제로 비트맵 파일을 불러오는것은 내부적으로 다른 함수를 거칩니다. 다른 압축된 형태의 이미지 파일들은 (jpg등) SDL_image라는 추가 라이브러리로 로드 할 수 있습니다. (추후에 다루겠습니다.)
이미지를 로드하지 못했다면 SDL_LoadBMP은 NULL을 반환합니다. 그에따른 예외처리를 하고 오류가 존재하지 않는다면 true를 반환합니다.
마지막 사용자 함수는 close()로 할당받은 리소스를 메모리에서 해제하고 SDL 서브시스템을 종료합니다. 작은 프로그램이라면 그냥 종료해도 상관없지만, 프로그램이 조금만 커지더라도 메모리 할당, 해제과정은 상당히 중요한 문제가 되므로 빼먹지 말도록 합시다.
01.
//리소스를 반환한다.
02.
void
close()
03.
{
04.
//서페이스 할당해제
05.
SDL_FreeSurface( gHelloWorld );
06.
gHelloWorld = NULL;
07.
08.
//윈도우 종료
09.
SDL_DestroyWindow( gWindow );
10.
gWindow = NULL;
11.
12.
//SDL 서브시스템 종료
13.
SDL_Quit();
14.
}
마지막으로 프로그램의 시작 지점인 main함수입니다.
01.
<p>
int
main(
int
argc,
char
* args[] ) {
02.
if
( !init() ) {
03.
printf
(
"Failed to initialize!\n"
);
04.
}
05.
else
06.
{
07.
if
( !loadMedia() ) {
08.
printf
(
"Failed to load media!\n"
);
09.
}
10.
else
{
11.
//이미지를 서페이스에 저장한다.
12.
SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
13.
14.
//서페이스 업데이트
15.
SDL_UpdateWindowSurface( gWindow );
16.
17.
//5초간 기다리기
18.
SDL_Delay( 5000 );
19.
}
20.
}
21.
close();
22.
return
0;
23.
}</p>
각 함수를 호출하고 실패한 예외상황에 대한 오류 메세지를 출력합니다. 예외처리는 오류가 어디서 발생했는지 쉽게 알 수 있게 해주기 때문에 디버깅에 큰 도움이 됩니다.
만약 모든 함수가 성공적으로 호출되었다면 로드된 이미지를 5초간 업데이트하며 보여주고 프로그램을 종료하는 프로그램입니다.
int SDL_BlitSurface( SDL_Suface *src, SDL_Rect *srcrect, SDL_Suface *dst,
SDL_Rect *dstrect);
여기서 SDL_Rect는 왼쪽 위 기준점과 너비, 높이를 가지는 사각형을 저장하는 객체입니다. Rect가 NULL이
라면 목표는 표면 전체가 됩니다. 주어진 원본 표면(src)을 srcrect따라 분할하여, 목적 표면(dst, 여기서는
x, y 좌표만을 사용합니다.)에 뿌려줍니다.
int SDL_UpdateWindowSurface(SDL_Window * window);
파라매터로 주어진 윈도우를 변동된 표면 상태에 따라서 업데이트합니다.
SDL_Delay( Uint32 ms );
파라매터로 주어진 ms(1000분의 1초)만큼의 시간을 대기합니다. 대기하는 동안에 프로세스는 CPU 점유를
다른 프로세스에게 넘겨주므로 컴퓨터 자원을 아낄 수 있습니다.
이상으로 코드 해석이 끝났습니다. 다음 시간에는 키보드와 마우스 입력 처리에 대해서 알아보겠습니다.
이번 강의의 코드 해석을 도울수 있는 숙제를 하나 준비했으니 한번 실습 해보시는 것도 좋습니다.
오늘의 숙제 : Rect 객체를 생성해 추가하고, SDL_BlitSurface() 함수에서 dstrect파라매터를 조작하여, 원운
동하는 그림을 출력해봅시다. (반복문이나 사용자 함수를 마음껏 만들어도 좋습니다.)
[SDL] 0. SDL의 시작 (1) | 2013.08.14 |
---|