유튜브에 올라와있는 'OpenTK' 플랫폼 튜토리얼을 따라하는 포스팅입니다.
'OpenTK'는 'OpenGL', 'OpenCL', 'OpenAL'가 합쳐진 C#랩퍼입니다.
OpenTK Platformer Tutorials: Part 2 - Loading and Drawing a Texture
텍스처를 불러오고 불러온 텍스처를 화면에 그리는 방법.
이 부분은 C#의 기초라고 할 수 있습니다.
프로젝트에 'Content'폴더를 만들고 텍스처로 사용할 이미지를 넣어 둡니다.
추가한 이미지를 클릭한 후 속성창에
빌드 작업 : 없음
출력 디렉터리로 복사 : 변경된 내용만 복사
로 변경 해줍니다.
이제 프로젝트를 실행해보면 디버그 폴더에 'Content'폴더가 만들어지고 추가한 이미지가 복사된 것을 볼 수 있습니다.
'콘텐츠 파이프' 클래스는 'OpenGL'을 이용하여 텍스처를 불러오는 클래스입니다.
class ContentPipe { public static int LoadTexture(string path) { if (!File.Exists("Content/" + path)) { throw new FileNotFoundException("파일을 찾을 수 없습니다. '" + path + "'"); } int id = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, id); Bitmap bmp = new Bitmap("Content/" + path); BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height) , ImageLockMode.ReadOnly , System.Drawing.Imaging.PixelFormat.Format32bppArgb); GL.TexImage2D(TextureTarget.Texture2D , 0 , PixelInternalFormat.Rgba , data.Width , data.Height , 0 , OpenTK.Graphics.OpenGL.PixelFormat.Bgra , PixelType.UnsignedByte , data.Scan0); bmp.UnlockBits(data); GL.TexParameter(TextureTarget.Texture2D , TextureParameterName.TextureWrapS , (int)TextureWrapMode.Clamp); GL.TexParameter(TextureTarget.Texture2D , TextureParameterName.TextureWrapT , (int)TextureWrapMode.Clamp); GL.TexParameter(TextureTarget.Texture2D , TextureParameterName.TextureMinFilter , (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D , TextureParameterName.TextureMagFilter , (int)TextureMagFilter.Linear); return id; } }
'GL.GenTexture()'를 이용하여 텍스처를 생성하고 생성된 텍스처의 아이디를 받아옵니다.
'GL.BindTexture'를 호출하여 생성한 텍스처가 2D임을 알립니다.
'GL.TexImage2D'는 만든 텍스처에 이미지를 저장해 줍니다.
다양한 파라메타가 있는데 'OpenGL'의 레퍼런스를 확인 하시면 됩니다.
'GL.TexParameter'는 거리나 확대/축소와 같은 상황에서 텍스처에 적용될 필터를 지정합니다
이것도 'OpenGL'의 레퍼런스를 확인 하시면 됩니다.
'Bitmap'과 'BitmapData'는 C#의 기능입니다.
제가 OpenGL을 잘 몰라서 이 코드가 어떻게 아이디에 텍스처를 입히는 건지 모르겠습니다 ㅎㅎㅎ
코드대로 하면 텍스처 아이디에 이미지가 올라갑니다.
'LoadTexture'를 이용하여 텍스처를 불러오고 불러온 텍스쳐를 서페이스에 적용 합니다.
클래스 변수로 'int texture'를 추가합니다.
클래스의 생성자에 'GL.Enable(EnableCap.Texture2D);'를 넣어 줍니다.
그 다음
'OnLoad'에서 'ContentPipe.LoadTexture'를 호출하여 텍스처 아이디를 받아 저장하도록 코드를 추가합니다.
protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.texture = ContentPipe.LoadTexture("supwergirl.jpg"); }
'OnRenderFrame'의 'GL.Begin'위에 'GL.BindTexture'를 추가하고 저장한 텍스처 아이디를 전달하여 서페이스에 텍스처를 표시해 줍니다.
'GL.Vertex2'위에 'GL.TexCoord2'를 추가하여 텍스처의 위치를 잡아 줍니다.
protected override void OnRenderFrame(FrameEventArgs e) { base.OnRenderFrame(e); GL.Clear(ClearBufferMask.ColorBufferBit); GL.ClearColor(Color.CornflowerBlue); GL.LoadIdentity(); GL.BindTexture(TextureTarget.Texture2D, this.texture); GL.Begin(PrimitiveType.Quads); GL.Color3(Color.Red); GL.TexCoord2(0, 0); GL.Vertex2(0, 0); //Top, Left GL.Color3(Color.Blue); GL.TexCoord2(1, 0); GL.Vertex2(1, 0); //Top, Right GL.Color3(Color.Orange); GL.TexCoord2(1, 1); GL.Vertex2(1, -1f); //Bottom, Right GL.Color3(Color.Green); GL.TexCoord2(0, 1); GL.Vertex2(0, -1); //Bottom, Left GL.End(); this.SwapBuffers(); }
이렇게 하면 서페이스에 텍스처가 올라가게 됩니다.
이제 'Texture2D' 구조체를 만들어 코드를 정리 합니다.
프로젝트에 'Texture2D' 클래스를 추가한 후 아래 코드와 같이 작성 합니다.
struct Texture2D { private int id; private int width, height; public int ID { get { return this.id; } } public int Width { get { return this.width; } } public int Height { get { return this.height; } } public Texture2D(int id, int width, int height) { this.id = id; this.width = width; this.height = height; } }
이 구조체를 이용하여 텍스처를 관리하면 됩니다.
'ContentPipe'로 가서
public static int LoadTexture(string path)
를
public static Texture2D LoadTexture(string path)
로 바꿔 줍니다.
return id;
를
return new Texture2D(id, bmp.Width, bmp.Height);
로 바꿔 줍니다.
이렇게 바꾸면 'Game'클래스에서 오류가 납니다.
int texture;
를
Texture2D texture;
로 바꿉니다.
'OnRenderFrame'의
GL.BindTexture(TextureTarget.Texture2D, this.texture);
을
GL.BindTexture(TextureTarget.Texture2D, this.texture.ID);
로 바꿉니다.
이제 실행시키면 똑같이 동작하게 됩니다.
'OpenGL'을 셈플가지고 개조해서 사용만 해봤지 분석을 해보질 않아서 코드를 설명하기가 힘드네요 ㅡ.-;;;;
아무래도 이번 기회에 공부 좀 해야겠습니다 ㅎㅎㅎ