이번에 소개할 오픈소스 라이브러리는 아직 좀 더 알아보고 있는 한 개발자가 개발한 2개 2D 그래픽 라이브러리입니다.
libxd는 C++기반 2D 그래픽 라이브러리며 그래픽 응용 프로그램을 만들 수 있는 직관적인 함수 모음을 제공하는 C++ 라이브러리입니다. 게임, 예술적 시각화 또는 고도로 정교한 물리 시뮬레이션을 할 수 있으며 libxd는 C++를 배우기 위한 도구로도 사용할 수 있습니다. OpenGL 기반이기 때문에 libxd는 하드웨어 가속 렌더링을 할 수 있다고 하는데 OpenGL 관련 API 호출되는 것은 아니라고 합니다. 지금 2D 그래픽 라이브러리에 초점을 잡고 있지만 장기적으로는 3D까지 구현도 곧 가능할 것으로 보입니다. libxd는 Linux, macOS 및 Windows를 지원합니다.
piksel도 libxd 라이브러리처럼 C++기반 2D 그래픽 라이브러리지만 차이점은 하드웨어 가속 렌더링 WebAssembly로 컴파일 가능 Processing과 유사한 직관적인 API라고 나와있습니다. 즉, C++로 구현한 것을 웹으로 컴파일이 가능하다는 특징이 있습니다. C++로 간단한 게임을 웹으로 구동하길 원한다면 WebAssembly로 통해서 할 수 있다는 말로 설명하면 되겠습니다.
libxd / piksel은 (libxd: LGPL-2.1 라이선스 / piksel: MIT 라이선스) 오스트리아 출신 개발자 Bernhard Fritz가 오픈소스로 개발한 2개의 C++기반 2D 그래픽 라이브러리입니다. 개발자의 말에 의하면 libxd는 Processing 및 p5.js 프로젝트에 영감을 받아서 개발했다고 하는데, 기본 예제 코드를 보면 Processing 와 p5.js 기본 코드 골격과 비슷하게 생겼습니다.
libxd 기본 코드 예제 - Hello rectangle!
#include <xd/xd.hpp>
using namespace xd;
void setup() {
size(640, 480);
}
void draw() {
rect(50, 50, 100, 100);
}
void destroy() {
}
piksel shape.cpp (with OpenGL GLM) 예제 코드
#include "shader.hpp"
#include <glm/gtc/type_ptr.hpp>
#include <fstream>
#include <sstream>
namespace piksel {
std::string readFile(const std::string& filename) {
std::ifstream ifs(filename.c_str());
std::stringstream ss;
ss << ifs.rdbuf();
return ss.str();
}
GLuint compile(GLenum shaderType, const std::string &shaderSource) {
GLuint shader = glCreateShader(shaderType);
const GLchar* c_str = shaderSource.c_str();
glShaderSource(shader, 1, &c_str, NULL);
glCompileShader(shader);
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar infoLog[infoLogLength];
glGetShaderInfoLog(shader, infoLogLength, &infoLogLength, infoLog);
glDeleteShader(shader);
fprintf(stderr, "Shader compilation failed: %s\n", infoLog);
return 0;
}
return shader;
}
GLuint link(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if(linkStatus == GL_FALSE) {
GLint infoLogLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar infoLog[infoLogLength];
glGetProgramInfoLog(program, infoLogLength, &infoLogLength, infoLog);
glDeleteProgram(program);
fprintf(stderr, "Program linking failed: %s\n", infoLog);
return 0;
}
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);
return program;
}
void Shader::create(const std::string &vertexShaderSource, const std::string &fragmentShaderSource) {
GLuint vertexShader;
if ((vertexShader = compile(GL_VERTEX_SHADER, vertexShaderSource)) > 0) {
GLuint fragmentShader;
if ((fragmentShader = compile(GL_FRAGMENT_SHADER, fragmentShaderSource)) > 0) {
program = link(vertexShader, fragmentShader);
}
}
}
void Shader::load(const std::string &vertexShaderFilename, const std::string &fragmentShaderFilename) {
create(readFile(vertexShaderFilename), readFile(fragmentShaderFilename));
}
void Shader::createUniform(const std::string &uniformName) {
uniforms[uniformName] = glGetUniformLocation(program, uniformName.c_str());
}
void Shader::setUniform(const std::string &uniformName, const int &i) {
glUniform1iv(uniforms[uniformName], 1, &i);
}
void Shader::setUniform(const std::string &uniformName, const float &f) {
glUniform1fv(uniforms[uniformName], 1, &f);
}
void Shader::setUniform(const std::string &uniformName, const glm::vec2 &v) {
glUniform2fv(uniforms[uniformName], 1, glm::value_ptr(v));
}
void Shader::setUniform(const std::string &uniformName, const glm::vec3 &v) {
glUniform3fv(uniforms[uniformName], 1, glm::value_ptr(v));
}
void Shader::setUniform(const std::string &uniformName, const glm::vec4 &v) {
glUniform4fv(uniforms[uniformName], 1, glm::value_ptr(v));
}
void Shader::setUniform(const std::string &uniformName, const glm::mat4 &m) {
glUniformMatrix4fv(uniforms[uniformName], 1, GL_FALSE, glm::value_ptr(m));
}
void Shader::use() {
if (program) {
glUseProgram(program);
}
}
} // namespace nv
여전히 알아보고 있는 라이브러리로 다양한 테스트와 예제를 통해서 공부해보고 구현해봐야 알 수 있을 것 같습니다. 관심있는 분 공식 웹사이트에 방문해보시기 바랍니다. 관련 깃허브에서 다운로드할 수 있습니다.
최근에는 C / C++, Java, JavaScript, TypeScript언어도 지원하는 2D 그래픽 라이브러리 "p8g"라는 언어도 공개 했으니 검색해보시기 바랍니다. (웹에디터도 있음)
p8g (Precessing) 기본 코드
import p8g, {
background,
createCanvas,
rect,
} from 'https://unpkg.com/p8g.js';
p8g.draw = () => {
background(220);
rect(50, 50, 100, 100);
};
createCanvas(320, 320);
*Bernhard Fritz의 itch.io페이지에는 piksel 라이브러리로 만든 Mario breaks out 게임 (piksel 공식 페이지 예제에도 있고 깃허브 페이지에도 itch.io페이지 링크 있음)이 있습니다.
====================================
구글 검색창에 "libxd 라이브러리 & piksel 라이브러리" 검색


댓글