Examples
Practical code examples showing meta-gl's type-safe API side by side with the equivalent raw OpenGL calls.
Initialization
#include <metagl/metagl.hpp> // Works with SDL2, GLFW, EGL, or any GetProcAddress-compatible function: bool ok = metagl::Initialize(SDL_GL_GetProcAddress); if (!ok) { fprintf(stderr, "Failed to load core GL functions\n"); return EXIT_FAILURE; } const auto& caps = metagl::GetCapabilities(); printf("Renderer: %s\n", caps.renderer.c_str()); printf("ES3.1: %d ES3.2: %d\n", caps.gles31, caps.gles32);
Clear Screen
Raw OpenGL
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT);
meta-gl
metagl::glClearColor(0.1f, 0.1f, 0.1f, 1.0f); metagl::glClear( metagl::ClearBufferBit::Color | metagl::ClearBufferBit::Depth);
Triangle (VAO + VBO + shader)
#include <metagl/metagl.hpp> #include <array> static const char* vert = R"(#version 300 es layout(location=0) in vec2 aPos; void main() { gl_Position = vec4(aPos, 0.0, 1.0); })"; static const char* frag = R"(#version 300 es precision mediump float; out vec4 color; void main() { color = vec4(1.0, 0.5, 0.2, 1.0); })"; static auto compileShader(metagl::ShaderType type, const char* src) { GLuint id = metagl::glCreateShader(type); metagl::glShaderSource(id, 1, &src, nullptr); metagl::glCompileShader(id); GLint ok = 0; metagl::glGetShaderiv(id, metagl::ShaderParameter::CompileStatus, &ok); if (!ok) { char log[512]; metagl::glGetShaderInfoLog(id, sizeof(log), nullptr, log); fprintf(stderr, "Shader error: %s\n", log); } return id; } GLuint buildProgram() { GLuint vs = compileShader(metagl::ShaderType::Vertex, vert); GLuint fs = compileShader(metagl::ShaderType::Fragment, frag); GLuint prog = metagl::glCreateProgram(); metagl::glAttachShader(prog, vs); metagl::glAttachShader(prog, fs); metagl::glLinkProgram(prog); metagl::glDeleteShader(vs); metagl::glDeleteShader(fs); return prog; } GLuint vao, vbo; void setupTriangle() { std::array<float, 6> verts = { -0.5f, -0.5f, 0.5f, -0.5f, 0.0f, 0.5f }; metagl::glGenVertexArrays(1, &vao); metagl::glBindVertexArray(vao); metagl::glGenBuffers(1, &vbo); metagl::glBindBuffer(metagl::BufferTarget::Array, vbo); metagl::glBufferData(metagl::BufferTarget::Array, (GLsizeiptr)(verts.size() * sizeof(float)), verts.data(), metagl::BufferUsage::StaticDraw); metagl::glEnableVertexAttribArray(0); metagl::glVertexAttribPointer(0, 2, metagl::DataType::Float, GL_FALSE, 2 * sizeof(float), nullptr); } void drawTriangle() { metagl::glBindVertexArray(vao); metagl::glDrawArrays(metagl::PrimitiveType::Triangles, 0, 3); }
Texture Upload
void uploadRGBATexture(const uint8_t* pixels, int w, int h) { GLuint tex; metagl::glGenTextures(1, &tex); metagl::glBindTexture(metagl::TextureTarget::Texture2D, tex); // Set wrapping and filtering: metagl::glTexParameteri(metagl::TextureTarget::Texture2D, metagl::TextureParameter::WrapS, (GLint)metagl::TextureWrapMode::ClampToEdge); metagl::glTexParameteri(metagl::TextureTarget::Texture2D, metagl::TextureParameter::WrapT, (GLint)metagl::TextureWrapMode::ClampToEdge); metagl::glTexParameteri(metagl::TextureTarget::Texture2D, metagl::TextureParameter::MinFilter, (GLint)metagl::TextureMinFilter::LinearMipmapLinear); metagl::glTexParameteri(metagl::TextureTarget::Texture2D, metagl::TextureParameter::MagFilter, (GLint)metagl::TextureMagFilter::Linear); // Upload pixel data: metagl::glPixelStorei(metagl::PixelStoreParam::UnpackAlignment, 1); metagl::glTexImage2D(metagl::TextureTarget::Texture2D, 0, metagl::InternalFormat::Rgba8, w, h, 0, metagl::PixelFormat::Rgba, metagl::PixelType::UnsignedByte, pixels); metagl::glGenerateMipmap(metagl::TextureTarget::Texture2D); }
Uniform Buffer Object (ES 3.0+)
// Example: per-frame camera matrices in a UBO struct FrameData { float view[16]; float proj[16]; }; GLuint ubo; metagl::glGenBuffers(1, &ubo); metagl::glBindBuffer(metagl::BufferTarget::Uniform, ubo); metagl::glBufferData(metagl::BufferTarget::Uniform, sizeof(FrameData), nullptr, metagl::BufferUsage::DynamicDraw); // Bind to binding point 0: metagl::glBindBufferBase(metagl::BufferTarget::Uniform, 0, ubo); // Per-frame update: FrameData frame = { /* ... */ }; metagl::glBindBuffer(metagl::BufferTarget::Uniform, ubo); metagl::glBufferSubData(metagl::BufferTarget::Uniform, 0, sizeof(frame), &frame); // In shader: layout(binding=0, std140) uniform FrameData { mat4 view; mat4 proj; }; // In program: link binding index to UBO slot GLuint blockIdx = metagl::glGetUniformBlockIndex(prog, "FrameData"); metagl::glUniformBlockBinding(prog, blockIdx, 0);
Offscreen Framebuffer (Render to Texture)
GLuint fbo, colorTex, depthRbo; void createFBO(int w, int h) { // Color attachment — immutable texture (ES 3.0) metagl::glGenTextures(1, &colorTex); metagl::glBindTexture(metagl::TextureTarget::Texture2D, colorTex); metagl::glTexStorage2D(metagl::TextureTarget::Texture2D, 1, metagl::InternalFormat::Rgba8, w, h); // Depth attachment — renderbuffer metagl::glGenRenderbuffers(1, &depthRbo); metagl::glBindRenderbuffer(metagl::RenderbufferTarget::Renderbuffer, depthRbo); metagl::glRenderbufferStorage(metagl::RenderbufferTarget::Renderbuffer, metagl::InternalFormat::DepthComponent24, w, h); // Assemble FBO metagl::glGenFramebuffers(1, &fbo); metagl::glBindFramebuffer(metagl::FramebufferTarget::Framebuffer, fbo); metagl::glFramebufferTexture2D( metagl::FramebufferTarget::Framebuffer, metagl::FramebufferAttachment::Color0, metagl::TextureTarget::Texture2D, colorTex, 0); metagl::glFramebufferRenderbuffer( metagl::FramebufferTarget::Framebuffer, metagl::FramebufferAttachment::Depth, metagl::RenderbufferTarget::Renderbuffer, depthRbo); // Verify completeness auto status = metagl::glCheckFramebufferStatus( metagl::FramebufferTarget::Framebuffer); if (status != metagl::FramebufferStatus::Complete) { fprintf(stderr, "FBO incomplete\n"); } } void renderToFBO() { metagl::glBindFramebuffer(metagl::FramebufferTarget::Framebuffer, fbo); // ... render scene ... metagl::glBindFramebuffer(metagl::FramebufferTarget::Framebuffer, 0); }
Instanced Drawing (ES 3.0+)
// Per-instance data: translation offsets std::array<float, 200> offsets; // 100 instances × vec2 // ... fill offsets ... GLuint instanceVbo; metagl::glGenBuffers(1, &instanceVbo); metagl::glBindBuffer(metagl::BufferTarget::Array, instanceVbo); metagl::glBufferData(metagl::BufferTarget::Array, sizeof(offsets), offsets.data(), metagl::BufferUsage::StaticDraw); // Attribute index 1 = per-instance offset metagl::glEnableVertexAttribArray(1); metagl::glVertexAttribPointer(1, 2, metagl::DataType::Float, GL_FALSE, 2 * sizeof(float), nullptr); metagl::glVertexAttribDivisor(1, 1); // advance once per instance // Draw 100 instances of the base mesh: metagl::glDrawArraysInstanced(metagl::PrimitiveType::Triangles, 0, 3, 100);
Compute Shader (ES 3.1+)
static const char* computeSrc = R"(#version 310 es layout(local_size_x=64) in; layout(std430, binding=0) buffer Data { float values[]; }; void main() { uint idx = gl_GlobalInvocationID.x; values[idx] *= 2.0; })"; void runCompute(GLuint ssbo, GLuint elementCount) { GLuint cs = metagl::glCreateShader(metagl::ShaderType::Compute); metagl::glShaderSource(cs, 1, &computeSrc, nullptr); metagl::glCompileShader(cs); GLuint prog = metagl::glCreateProgram(); metagl::glAttachShader(prog, cs); metagl::glLinkProgram(prog); metagl::glUseProgram(prog); // Bind SSBO to binding 0: metagl::glBindBufferBase(metagl::BufferTarget::ShaderStorage, 0, ssbo); // Dispatch: 64 threads per group, ceil(elementCount/64) groups GLuint groups = (elementCount + 63) / 64; metagl::glDispatchCompute(groups, 1, 1); // Ensure writes are visible to subsequent reads: metagl::glMemoryBarrier(metagl::MemoryBarrierMask::ShaderStorage); }
Alpha Blending Setup
// Standard "over" blending for transparent objects: metagl::glEnable(metagl::Capability::Blend); metagl::glBlendFunc(metagl::BlendFactor::SrcAlpha, metagl::BlendFactor::OneMinusSrcAlpha); metagl::glBlendEquation(metagl::BlendEquation::FuncAdd); // Premultiplied alpha (for ASTC/HDR textures): metagl::glBlendFunc(metagl::BlendFactor::One, metagl::BlendFactor::OneMinusSrcAlpha);
Stencil Masking
// Pass 1: write stencil mask metagl::glEnable(metagl::Capability::StencilTest); metagl::glStencilFunc(metagl::CompareFunc::Always, 1, 0xFF); metagl::glStencilOp(metagl::StencilOp::Keep, metagl::StencilOp::Keep, metagl::StencilOp::Replace); metagl::glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); drawMaskShape(); // Pass 2: render only where stencil == 1 metagl::glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); metagl::glStencilFunc(metagl::CompareFunc::Equal, 1, 0xFF); metagl::glStencilOp(metagl::StencilOp::Keep, metagl::StencilOp::Keep, metagl::StencilOp::Keep); drawScene();
Error Handling
// Inline error check helper: inline void checkGLError(const char* context) { auto err = metagl::glGetError(); if (err != metagl::ErrorCode::NoError) { fprintf(stderr, "GL error at %s: 0x%X\n", context, static_cast<unsigned>(err)); } } // Usage: metagl::glLinkProgram(prog); checkGLError("glLinkProgram"); // Possible error codes: // ErrorCode::NoError — no error // ErrorCode::InvalidEnum — bad enum value // ErrorCode::InvalidValue — bad parameter value // ErrorCode::InvalidOperation — invalid state // ErrorCode::OutOfMemory — allocation failed // ErrorCode::InvalidFramebufferOperation — FBO not complete