앱 개발

이승훈·2025년 9월 9일

개발 환경

C 컴파일러 설치

sudo apt update
sudo apt upgrade
sudo apt install build-essential

SDL2 라이브러리 설치

sudo apt install libsdl2-dev

SDL2_ttf 라이브러리 설치

sudo apt install libsdl2-ttf-dev

OpenGL ES 2.0 라이브러리 설치

sudo apt install libgles2-mesa-dev libegl1-mesa-dev

컴파일

gcc -o app app.c `sdl2-config --cflags --libs` -lSDL2_ttf -lGLESv2

역할 분담

라이브러리역할
standard I/O콘솔 입출력
SDL2창, 멀티미디어, 입력, 이벤트
SDL2_ttf텍스트 렌더링 (TTF 폰트)
OpenGL ES 2.0그래픽

사실 SDL2 만으로도 그래픽 처리를 할 수 있지만 2D 와 픽셀 기반이라는 제한이 있다. 3D 나 벡터 기반의 그래픽 작업을 위해 OpenGL 을 사용한다.

참고 코드1

#include <SDL2/SDL.h>
#include <GLES2/gl2.h>
#include <stdio.h>

int main() {
  int w = 0;
  int h = 0;
  int quit = 0;

  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    printf("SDL_Init Error: %s\n", SDL_GetError());
    return -1;
  }

  SDL_Event event;

  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

  SDL_Window* window = SDL_CreateWindow(
    "SDL2 + GLES2 (blue clear)",
    SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
    w, h,
    SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN
  );
  if (!window) {
    printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
    SDL_Quit();
    return -1;
  }
  SDL_GetWindowSize(window, &w, &h);

  SDL_GLContext ctx = SDL_GL_CreateContext(window);
  if (!ctx) {
    printf("SDL_GL_CreateContext Error: %s\n", SDL_GetError());
    SDL_DestroyWindow(window);
    SDL_Quit();
    return -1;
  }

  SDL_GL_SetSwapInterval(1);
  printf("Current Swap Interval: %d\n", SDL_GL_GetSwapInterval());

  glViewport(0, 0, w, h);
  glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN) {
        quit = 1;
      }

      glClear(GL_COLOR_BUFFER_BIT);
      SDL_GL_SwapWindow(window);
    }
  }

  SDL_GL_DeleteContext(ctx);
  SDL_DestroyWindow(window);
  SDL_Quit();

  return 0;
}

참고 코드2

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <GLES2/gl2.h>
#include <stdio.h>

static const char* vs_src =
  "attribute vec2 aPos;\n"
  "attribute vec2 aUV;\n"
  "varying vec2 vUV;\n"
  "void main(){ vUV=aUV; gl_Position=vec4(aPos,0.0,1.0); }\n";

static const char* fs_src =
  "precision mediump float;\n"
  "varying vec2 vUV;\n"
  "uniform sampler2D uTex;\n"
  "void main(){ gl_FragColor=texture2D(uTex,vUV); }\n";

GLuint compile(GLenum type,const char*src){
  GLuint s=glCreateShader(type);
  glShaderSource(s,1,&src,NULL);
  glCompileShader(s);
  return s;
}

int main(){
  int w=800,h=600,quit=0;
  SDL_Init(SDL_INIT_VIDEO);
  TTF_Init();

  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,SDL_GL_CONTEXT_PROFILE_ES);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,2);
  SDL_Window* win=SDL_CreateWindow("Hello GLES2",0,0,w,h,SDL_WINDOW_OPENGL);
  SDL_GLContext ctx=SDL_GL_CreateContext(win);

  // 프로그램
  GLuint vs=compile(GL_VERTEX_SHADER,vs_src);
  GLuint fs=compile(GL_FRAGMENT_SHADER,fs_src);
  GLuint prog=glCreateProgram();
  glAttachShader(prog,vs); glAttachShader(prog,fs);
  glBindAttribLocation(prog,0,"aPos");
  glBindAttribLocation(prog,1,"aUV");
  glLinkProgram(prog);

  // 폰트 → Surface
  TTF_Font* font=TTF_OpenFont("NanumGothic.ttf",64);
  SDL_Color white={255,255,255,255};
  SDL_Surface* s1=TTF_RenderUTF8_Blended(font,"Hello, World!",white);
  SDL_Surface* s2=SDL_ConvertSurfaceFormat(s1,SDL_PIXELFORMAT_ABGR8888,0);
  SDL_FreeSurface(s1);

  // 텍스처 생성
  GLuint tex; glGenTextures(1,&tex);
  glBindTexture(GL_TEXTURE_2D,tex);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,s2->w,s2->h,0,
               GL_RGBA,GL_UNSIGNED_BYTE,s2->pixels);
  SDL_FreeSurface(s2);

  // 중앙 위치 계산
  float tw=(float)s2->w, th=(float)s2->h;
  float cx=(w-tw)/2.0f, cy=(h-th)/2.0f;
  float l=2*cx/w-1, r=2*(cx+tw)/w-1;
  float t=1-2*cy/h, b=1-2*(cy+th)/h;

  GLfloat verts[]={
    l,t, 0,0,  r,t,1,0,  r,b,1,1,
    l,t, 0,0,  r,b,1,1,  l,b,0,1
  };
  GLuint vbo; glGenBuffers(1,&vbo);
  glBindBuffer(GL_ARRAY_BUFFER,vbo);
  glBufferData(GL_ARRAY_BUFFER,sizeof(verts),verts,GL_STATIC_DRAW);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

  SDL_Event e;
  while(!quit){
    while(SDL_PollEvent(&e)){
      if(e.type==SDL_QUIT||e.type==SDL_KEYDOWN) quit=1;
    }
    glViewport(0,0,w,h);
    glClearColor(0,0,1,1); glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(prog);
    glBindTexture(GL_TEXTURE_2D,tex);
    glBindBuffer(GL_ARRAY_BUFFER,vbo);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(0,2,GL_FLOAT,0,4*sizeof(float),(void*)0);
    glVertexAttribPointer(1,2,GL_FLOAT,0,4*sizeof(float),(void*)(2*sizeof(float)));
    glDrawArrays(GL_TRIANGLES,0,6);
    SDL_GL_SwapWindow(win);
  }

  // 정리
  glDeleteProgram(prog);
  glDeleteTextures(1,&tex);
  glDeleteBuffers(1,&vbo);
  TTF_CloseFont(font);
  SDL_GL_DeleteContext(ctx);
  SDL_DestroyWindow(win);
  TTF_Quit(); SDL_Quit();
  return 0;
}

필요 파일: NanumGothic.ttf

profile
안녕하세요!

0개의 댓글