2014년 7월 23일

SDL2 기반의 OPENGL 테스트 프레임워크

SDL (Simple DirectMedia Layer) 라이브러리는 수많은 게임들에 적용된 유명한 오픈소스 프로젝트 인데, 그래픽 환경을 보면 2D 기반임을 알 수 있다.


이를 OpenGL로 변경하여 손쉽게 개발환경을 구축해 보자. 참고로 버전업된 SDL2 가 최신버전이므로 이를 기반으로 OpenGL 테스트용 환경을 만들어 보자.
기본 구조는 https://github.com/MetaCipher/sdl-2.0-basics 을 참고하였으며, 입맞에 맞게 대폭 수정하였다.

SDL 이 처음이신분들은 http://lazyfoo.net/tutorials/SDL/index.php 에서 다양한 예제를 제공하고 있으니 방문 바란다.

사용된 SDL2 버전은 2.0.3 이며 OpenGL2.1 및 1024*768 해상도에서 동작한다.


1. App.h
#ifndef APP_H
#define APP_H

/*******************************************************************************

  SDL2 Demo Application

        ----------------
        | App          |
        ----------------
        | Execute      |
        | OnInit       |
        | OnEvent      |
        | OnLoop       |
        | OnRender     |
        | OnCleanUp    |
        ----------------
            /|\
             |
             |
             |
         your inherited class

  email : sepwind@gmail.com (blog : http://sepwind.blogspot.com)
  base code from : https://github.com/MetaCipher/sdl-2.0-basics (Tim Jones @ SDLTutorials.com)
  and revisied by sepwind.

*******************************************************************************/

#include "SDL.h"
#include "SDL_opengl.h"
#include <gl\gl.h>
#include <gl\glu.h>
#include <stdio.h>
#include <tchar.h>

#pragma comment(lib, "sdl2.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")


class App
{
protected:
   int _windowWidth;
   int _windowHeight;
   bool _running;
   SDL_Window* _pWindow;
   SDL_GLContext _glcontext;

private:
   bool Init();
   bool InitGL();
   void Render();
   void CleanUp();

public:
   virtual bool OnInit(int argc, TCHAR* argv[])=0;
   virtual void OnEvent(SDL_Event* Event)=0;
   virtual void OnLoop()=0;
   virtual void OnRender()=0;
   virtual void OnCleanUp()=0;

public:
   App();
   virtual ~App();
   int Execute(int argc, TCHAR* argv[]);
   int GetWindowWidth();
   int GetWindowHeight();
};

#endif


2. App.cpp


#include "app.h"
#include "log.h"

App::App()
{
   _running = true;
   _pWindow = NULL;
   _glcontext = NULL; 
   _windowWidth = 1024;
   _windowHeight = 768;
}

App::~App()
{
}

int App::GetWindowWidth()  { return _windowWidth; }
int App::GetWindowHeight() { return _windowHeight; }

bool App::Init()
{
   if(SDL_Init(SDL_INIT_VIDEO) < 0)
   {
      Log("Unable to Init SDL: %s", SDL_GetError());
      return false;
   }

   if(!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
   {
      Log("Unable to Init hinting: %s", SDL_GetError());
   }

   if((_pWindow = SDL_CreateWindow(
       "SDL2 DEMO - sepwind@gmail.com (http://sepwind.blogspot.kr)",
       SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
       _windowWidth, _windowHeight, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL)) == NULL)
   {
      Log("Unable to create SDL Window: %s", SDL_GetError());
      return false;
   }
 
   _glcontext = SDL_GL_CreateContext(_pWindow);
   SDL_GL_SetSwapInterval(1);

   this->InitGL();
   Log("success to initialized ... ");
   return true;
}

bool App::InitGL()
{
    glShadeModel( GL_SMOOTH );
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    glClearDepth( 1.0f );
    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LEQUAL );
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
  
    GLfloat ratio = ( GLfloat )_windowWidth / ( GLfloat )_windowHeight;
    glViewport( 0, 0, ( GLsizei )_windowWidth, ( GLsizei )_windowHeight );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0f, ratio, 0.1f, 1000.0f ); // z-near/far

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    return true;
}

void App::Render()
{
   SDL_GL_MakeCurrent(_pWindow, _glcontext);
   this->OnRender();
   SDL_GL_SwapWindow(_pWindow);
}

void App::CleanUp()
{
   Log("cleaning up ... ");
   this->OnCleanUp();
   if (_glcontext)
   {
      SDL_GL_DeleteContext(_glcontext);
      _glcontext = NULL;
   }
   if(_pWindow)
   {
      SDL_DestroyWindow(_pWindow);
      _pWindow = NULL;
   }
   SDL_Quit();
}

int App::Execute(int argc, TCHAR* argv[])
{
   if(!this->Init())
   {
      Log("fail to initialize SDL2");
      return -1;
   }

   if (false == this->OnInit(argc, argv))
   {
      Log("fail to initialize OnInit");
      return -1;
   }

   SDL_Event e;
   while(_running)
   {
      while(SDL_PollEvent(&e) != 0)
      {
       this->OnEvent(&e);
       if(e.type == SDL_QUIT)
       {
          _running = false;
       }
    }
    this->OnLoop();
    this->Render();
    SDL_Delay(0);
   }

   Log("stopping ... ");
   this->CleanUp();
   return 0;
}


3. Log.h


/*
 Basic macro for logging (can be extended for other target builds; i.e, using
 NSLog for OS X / iOS). Could also be modified to log to a file instead of
 console.

  3/11/2014
    SDLTutorials.com
    Tim Jones
*/

#ifndef LOG_H
#define LOG_H

#include <stdio.h>

#if defined(DEBUG) || defined(_DEBUG)
  #define Log(...) printf(__VA_ARGS__); printf( "\n" );
#else
  #define Log(...) ;
#endif

#endif




  • 제일 처음 할것은 App 클래스를 상속받아 필요한 함수를 구현해 주어야 한다.
  • 이후 명령행 인자들과 함께 Execute() 함수를 호출하여 가동을 시작한다.
  • 가동을 위해 최초 OnInit() 이벤트가 한번 발생하고, 
  • 사용자 입력(키보드, 마우스, 조이스틱 등)이 있을때 마다 OnEvent 가 발생한다.
  • 또한 게임로직등 다양한 일처리는 OnLoop 에서 구현하고
  • 매 프레임 렌더링 코드는 OnRender 에서 구현한다.
  • 프로그램 종료시에는 OnCleanUp 에 의해 자원회수 코드를 구현한다.


다음 글에서는 이를 기반으로 렌더링 데모를 시연해 보도록 하자.


댓글 없음:

댓글 쓰기

시리우스 라이브러리 홈페이지 오픈

현재 시리우스(Sirius) 라이브러리라는 제품을 개발하고 이를 소개하는 홈페이지를 오픈 하였습니다. 관심있는 분들의 많은 방문 요청드립니다. 앞으로 업데이트 소식및 변경사항은 스파이럴랩 홈페이지를 통해 진행할 예정입니다. 스파이럴랩 홈페이지 :  h...