voltar

PudimBasicsOpenGL

ver repo C★ 0

PudimBasicsGl - Pudim Basics OpenGL

A minimal 2D graphics library for Lua using OpenGL. PudimBasicsGl focuses on the essentials: window management, 2D rendering, textures, input, audio, text, time, camera, shaders, math, file utilities, and immediate-mode UI.

Warning

This project is experimental. APIs and features may change without notice — use with caution.

Versão em Português (PT-BR)

Features

  • Window: Create and manage OpenGL windows with VSync, fullscreen, and resize support
  • Renderer: Draw 2D primitives (pixels, lines, rectangles, circles, triangles, gradients) with automatic batch management
  • Textures: Load images (PNG, JPG, BMP, etc.) and draw them with rotation, tinting, chroma key, and sprite sheet support
  • Input: Keyboard and mouse input (key state, mouse position, cursor control)
  • Audio: Load and play audio files (WAV, MP3, FLAC) with volume, pitch, and looping via miniaudio
  • Text: Load TrueType fonts (.ttf) and render text with customizable size, color, and measurement via stb_truetype
  • Time: Delta time, FPS, and timing utilities
  • Camera: 2D camera controls (position, zoom, rotation, look_at, screen/world conversion)
  • Shader: Custom GLSL shaders — compile from strings or load from files, set uniforms (int, float, vec2-4, mat4)
  • Math: Vector math (vec2/vec3/vec4), arithmetic, lerp, clamp, angle conversion, and constants (PI, TAU)
  • Studio: File system utilities (list directory, file timestamps, file copy)
  • UI: Immediate-mode GUI widgets (panels, buttons, sliders, labels) for tools and debug overlays

Building

The recommended way to install is via LuaRocks (see below). For local development:

make

This creates PudimBasicsGl.so, a Lua module that you can load with require("PudimBasicsGl").

LSP Support

Add library/ to your lua-language-server library path for full autocomplete and type checking:

// .vscode/settings.json
{
    "Lua.workspace.library": ["./library"]
}

Or copy library/PudimBasicsGl.lua to your global lua-language-server addons folder.

Editor tip: Annotate variables with the qualified types to get method suggestions for instances. For example:

---@type PudimBasicsGl
local pb = require("PudimBasicsGl")

---@type PudimBasicsGl.Window
local win = pb.window.create(800, 600, "Title")

-- Now `win:` will show methods in VSCode's completion list
win:swap_buffers()

---@type PudimBasicsGl.Texture
local tex = pb.texture.load("sprite.png")
-- `tex:` will show texture methods such as `draw`, `get_size`, etc.

---@type Sound
local snd = pb.audio.load("music.mp3")
-- `snd:` will show audio methods such as `play`, `stop`, `set_volume`, etc.

---@type Font
local font = pb.text.load("my_font.ttf", 32)
-- `font:` will show text methods such as `draw`, `measure`, `set_size`, etc.

---@type Shader
local shd = pb.shader.create(vertex_src, fragment_src)
-- `shd:` will show shader methods such as `use`, `set_float`, `set_vec3`, etc.

Installation via LuaRocks

luarocks install pudimbasicsgl

Or build from the local rockspec:

luarocks make pudimbasicsgl-1.0.0-19.rockspec

The rockspec uses the builtin build type — LuaRocks compiles all .c sources directly into .so (Linux) or .dll (Windows), no makefile needed. The make command is only required for local development.

Usage

local pb = require("PudimBasicsGl")

-- Create a window
local window = pb.window.create(800, 600, "My App")
pb.renderer.init()

-- Load a texture (optional)
local texture = pb.texture.load("sprite.png")

-- Main loop (you control it!)
while not pb.window.should_close(window) do
    pb.time.update()
    local dt = pb.time.delta()
    
    -- Your game logic here
    
    -- Get current window size (handles resize)
    local w, h = pb.window.get_size(window)
    
    -- Render
    pb.renderer.clear(0.1, 0.1, 0.15, 1.0)
    pb.renderer.begin(w, h)
    
    -- Draw primitives
    pb.renderer.rect_filled(100, 100, 50, 50, pb.renderer.colors.RED)
    pb.renderer.circle_filled(400, 300, 30, {r=0, g=1, b=0.5, a=1})
    
    -- Draw textures (auto-flushes primitives!)
    if texture then
        texture:draw(200, 200)  -- Simple draw
        texture:draw_rotated(400, 400, 64, 64, 45)  -- Rotated 45 degrees
    end
    
    pb.renderer.finish()
    
    pb.window.swap_buffers(window)
    pb.window.poll_events()
end

if texture then texture:destroy() end
pb.window.destroy(window)

Input Example

-- Keyboard
if pb.input.is_key_pressed(pb.input.KEY_W) then
    player.y = player.y - speed * dt
end
if pb.input.is_key_pressed(pb.input.KEY_ESCAPE) then
    break
end

-- Mouse
local mx, my = pb.input.get_mouse_position()
if pb.input.is_mouse_button_pressed(pb.input.MOUSE_LEFT) then
    -- handle click
end

Audio Example

local music = pb.audio.load("music.mp3")
music:set_looping(true)
music:set_volume(0.8)
music:play()

-- Later...
music:pause()
music:resume()
music:stop()
music:destroy()

pb.audio.set_master_volume(0.5)
pb.audio.shutdown()

Text Example

-- Load a TrueType font at 32px
local font = pb.text.load("my_font.ttf", 32)

-- Draw text (auto-flushing handles switching from primitives)
font:draw("Hello, World!", 100, 100, 1, 1, 1) -- white text
font:draw("Colored!", 100, 150, {r=1, g=0.5, b=0, a=1}) -- orange text

-- Measure text dimensions
local w, h = font:measure("Hello, World!")

-- Change font size dynamically
font:set_size(48)

-- Cleanup
font:destroy()

API Reference

pb.window

Function Description
create(width, height, title) Create a window, returns window handle
destroy(window) Destroy window and free resources
should_close(window) Check if window should close
close(window) Signal window to close
swap_buffers(window) Present the rendered frame
poll_events() Process window events
get_size(window) Get window dimensions
set_size(window, w, h) Set window dimensions
set_title(window, title) Change window title
get_handle(window) Get native GLFW handle
set_vsync(window, enabled) Enable/disable VSync
get_vsync(window) Check if VSync is enabled
set_fullscreen(window, bool) Set fullscreen mode
is_fullscreen(window) Check if fullscreen
toggle_fullscreen(window) Toggle fullscreen mode
get_position(window) Get window position
set_position(window, x, y) Set window position
focus(window) Focus the window
is_focused(window) Check if window has focus
set_resizable(window, bool) Enable/disable resize

pb.renderer

Function Description
init() Initialize the renderer
clear(r, g, b, a) Clear screen with color
begin(width, height) Begin 2D rendering batch
finish() End rendering batch
flush() Flush without ending batch
pixel(x, y, color) Draw a point
line(x1, y1, x2, y2, color) Draw a line
rect(x, y, w, h, color) Draw rectangle outline
rect_filled(x, y, w, h, color) Draw filled rectangle
circle(x, y, radius, color) Draw circle outline
circle_filled(x, y, radius, color) Draw filled circle
triangle(...) Draw triangle outline
triangle_filled(...) Draw filled triangle
set_point_size(size) Set point rendering size
set_line_width(width) Set line rendering width
color(r, g, b, a) Create a color table (0.0-1.0 floats or hex)
color255(r, g, b, a) Create a color table from 0-255 integers
color_unpack(color) Unpack Color table → r, g, b, a (0.0-1.0)
set_clear_color(r, g, b, a?) Set OpenGL clear color state
enable_depth_test(enabled) Enable/disable OpenGL depth testing
enable_blend(enabled) Enable/disable alpha blending
set_viewport(x, y, width, height) Set the OpenGL viewport
get_info() Get OpenGL info table (version, renderer, vendor, glsl_version)
begin_ui(screen_width, screen_height) Begin screen-space rendering that ignores the camera
end_ui() End UI mode rendering
rect_gradient(x, y, w, h, top_color, bottom_color) Draw a vertical color gradient rectangle
read_pixel(x, y, screen_height) Read a pixel from the framebuffer (returns r, g, b, a)
colors.WHITE, colors.RED, etc. Predefined colors

pb.texture

Function Description
load(filepath) Load texture from file (PNG, JPG, BMP, TGA)
load_with_colorkey(filepath, hex_color) Load texture and make a specific color transparent
create(w, h, data?) Create texture with optional RGBA data
flush() Flush pending texture draws

Texture Methods

Method Description
texture:draw(x, y, w?, h?) Draw at position
texture:draw_tinted(x, y, w, h, r, g, b, a?) Draw with color tint
texture:draw_rotated(x, y, w, h, angle) Draw rotated (degrees)
texture:draw_ex(x, y, w, h, angle, ox, oy, r, g, b, a?) Full control draw
texture:draw_region(x, y, w, h, sx, sy, sw, sh) Draw sprite sheet region
texture:draw_region_ex(...) Region with rotation/tint
texture:get_size() Get width, height
texture:get_width() Get width
texture:get_height() Get height
texture:destroy() Free texture resources

pb.input

Function Description
is_key_pressed(key) Check if a key is currently held down
is_key_released(key) Check if a key is not held down
is_mouse_button_pressed(button) Check if a mouse button is held down
get_mouse_position() Get cursor position (x, y)
set_mouse_position(x, y) Set cursor position
set_cursor_visible(visible) Show/hide the cursor
set_cursor_locked(locked) Lock/unlock cursor (FPS-style)

Key Constants

KEY_A to KEY_Z, KEY_0 to KEY_9, KEY_SPACE, KEY_ESCAPE, KEY_ENTER, KEY_TAB, KEY_BACKSPACE, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1 to KEY_F3, KEY_F11, KEY_F12, KEY_LEFT_SHIFT, KEY_RIGHT_SHIFT, KEY_LEFT_CTRL, KEY_RIGHT_CTRL, KEY_LEFT_ALT, KEY_RIGHT_ALT

Mouse Constants

MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE

pb.audio

Function Description
load(filepath) Load audio file (WAV, MP3, FLAC), returns Sound
set_master_volume(volume) Set master volume (0.0–2.0)
get_master_volume() Get current master volume
shutdown() Shutdown audio engine

Sound Methods

Method Description
sound:play() Play from the beginning
sound:stop() Stop and rewind
sound:pause() Pause at current position
sound:resume() Resume from paused position
sound:is_playing() Check if playing
sound:set_looping(bool) Enable/disable looping
sound:is_looping() Check if looping
sound:set_volume(vol) Set volume (0.0 = silent, 1.0 = normal)
sound:get_volume() Get current volume
sound:set_pitch(pitch) Set pitch (1.0 = normal, 0.5 = slow, 2.0 = fast)
sound:get_pitch() Get current pitch
sound:destroy() Free sound resources

pb.text

Function Description
load(filepath, size?) Load a TrueType font (.ttf) at pixel size (default 24), returns Font
flush() Flush pending text draws

Font Methods

Method Description
font:draw(text, x, y, color) Draw text at position with color
font:measure(text) Get text width and height without drawing
font:set_size(size) Change font size (re-rasterizes atlas)
font:get_size() Get current font size in pixels
font:get_line_height() Get line height in pixels
font:destroy() Free font resources

pb.math

Function Description
lerp(a, b, t) Linear interpolation
clamp(val, min, max) Clamp value between min and max
radians(deg) Convert degrees to radians
degrees(rad) Convert radians to degrees
vec2(x, y) Create a 2D vector {x, y}
vec3(x, y, z) Create a 3D vector {x, y, z}
vec4(x, y, z, w) Create a 4D vector {x, y, z, w}
vec_add(a, b) Add vectors
vec_sub(a, b) Subtract vectors
vec_scale(v, s) Scale vector by scalar
vec_length(v) Calculate vector length
vec_normalize(v) Normalize vector
vec_dot(a, b) Dot product of vectors

Constants: pb.math.PI, pb.math.TAU, pb.math.HALF_PI

pb.studio

Function Description
list_dir(path) Returns a table of file names in the directory
get_file_modified_time(path) Get file modification timestamp (useful for hot-reload)
copy_file(src, dst) Copy a file from src to dst

pb.ui

Immediate-mode GUI widgets. First call set_font before the first frame.

Function Description
set_font(font) Set the font used by UI widgets
begin_frame() Begin a new UI frame (reads mouse state automatically)
end_frame() End current UI frame and draw everything
label(text, x, y, color) Draw a text label
panel(title, x, y, w, h) Draw a background panel with title
button(id, label, x, y, w, h, color) Draw an interactive button (returns true if clicked)
slider(id, label, x, y, w, h, val, min, max) Draw an interactive slider (returns updated value)

pb.shader

Function Description
create(vertex_src, fragment_src) Compile a shader from GLSL source strings, returns Shader
load(vertex_path, fragment_path) Load and compile shader from files, returns Shader
unuse() Unbind the current shader (restore default)

Shader Methods

Method Description
shader:use() Bind this shader for rendering
shader:unuse() Unbind this shader
shader:set_int(name, value) Set an integer uniform
shader:set_float(name, value) Set a float uniform
shader:set_vec2(name, x, y) Set a vec2 uniform
shader:set_vec3(name, x, y, z) Set a vec3 uniform
shader:set_vec4(name, x, y, z, w) Set a vec4 uniform
shader:set_mat4(name, {m1..m16}) Set a mat4 uniform (16 floats, column-major)
shader:get_id() Get the OpenGL program ID
shader:is_valid() Check if the shader compiled successfully
shader:destroy() Free shader GPU resources

pb.time

Function Description
update() Update time system (call once per frame)
delta() Get time since last frame
get() Get total time since init
fps() Get current FPS
sleep(seconds) Busy-wait sleep

pb.camera

Function Description
set_position(x, y) Set camera world offset (0,0 = no offset)
get_position() Get camera position → x, y
move(dx, dy) Move camera by delta
set_zoom(zoom) Set zoom level (1.0 = normal, >1 = zoom in)
get_zoom() Get current zoom level
set_rotation(angle) Set rotation in degrees
get_rotation() Get rotation in degrees
look_at(x, y, sw, sh) Center camera on world point
reset() Reset to defaults (pos=0,0 zoom=1 rot=0)
screen_to_world(sx, sy) Convert screen → world coordinates
world_to_screen(wx, wy) Convert world → screen coordinates

Color Format

Colors can be passed as:

  • Table: {r=1.0, g=0.5, b=0.0, a=1.0}
  • Individual values: r, g, b, a (alpha optional, defaults to 1.0)

Shader Example

-- Create a custom fragment shader
local vs = [[
#version 330 core
layout(location = 0) in vec2 aPos;
void main() { gl_Position = vec4(aPos, 0.0, 1.0); }
]]
local fs = [[
#version 330 core
out vec4 FragColor;
uniform float uTime;
void main() {
    FragColor = vec4(sin(uTime)*0.5+0.5, 0.3, 0.8, 1.0);
}
]]

local shader = pb.shader.create(vs, fs)
shader:use()
shader:set_float("uTime", pb.time.get())
-- draw geometry ...
shader:unuse()
shader:destroy()

Examples

We provide several example scripts in the examples/ directory. A new OOP-style demo demonstrates the object-style API (method calls via :) — it shows window:should_close(), texture:draw(), pb.time:update() and a simple render loop.

Run the demo after building/installing the module locally:

# Build/install locally (optional)
luarocks make --local

# Run example (ensures local .so is in package.cpath)
lua -e "package.cpath='./?.so;'..package.cpath" examples/oop_demo.lua

You can also inspect scripts/test_oop.lua for a minimal non-visual smoke test of the object-style API.

Dependencies

  • GLFW3
  • OpenGL 3.3+
  • Lua 5.4 or 5.5

Building

Linux

make

The makefile auto-detects your Lua version. To build for a specific version:

make LUA_VERSION=5.4   # Force Lua 5.4
make LUA_VERSION=5.5   # Force Lua 5.5

Windows (MSYS2/MinGW)

  1. Install MSYS2 and open the MinGW64 terminal
  2. Install dependencies:
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-glfw mingw-w64-x86_64-lua
  1. Build:
make

This creates PudimBasicsGl.dll. Use with:

-- Windows
package.cpath = ".\\?.dll;" .. package.cpath
local pb = require("PudimBasicsGl")

Example Scripts

  • examples/main.lua - Basic rendering demo
  • examples/minimal.lua - Minimal example
  • examples/texture_demo.lua - Texture loading and drawing
  • examples/window_demo.lua - VSync and window features
  • examples/input_demo.lua - Keyboard and mouse input demo
  • examples/audio_demo.lua - Audio loading and playback demo
  • examples/oop_demo.lua - Object-oriented style API demo
  • examples/text_demo.lua - Text rendering and font loading demo
  • examples/camera_demo.lua - 2D camera pan, zoom, rotation and coordinate conversion demo
  • examples/shader_demo.lua - Custom GLSL shader with animated color wave effect
  • examples/api_reference.lua - Complete API reference example

Command-line tool (pbgl)

A small CLI named pbgl is installed with the rock. It provides two commands:

  • pbgl show-examples — Copy bundled example scripts to ./demos/ in the current directory
  • pbgl help — Show usage information

After running pbgl show-examples you'll have a ./demos/ folder; run an example with:

lua demos/main.lua

Make sure ~/.luarocks/bin is in your PATH so you can call pbgl directly:

export PATH="$HOME/.luarocks/bin:$PATH"

Credits

  • Sample audio file (examples/example.mp3) from file-examples.com — used for testing/demo purposes only.
  • miniaudio — single-header audio library by David Reid (public domain / MIT-0).
  • stb_image — single-header image loader by Sean Barrett (public domain / MIT).
  • stb_truetype — single-header TrueType font rasterizer by Sean Barrett (public domain / MIT).
  • GLAD — OpenGL loader generator.

License

MIT