Overview
AXSLC is the Astralix Shader Language Compiler. It compiles .axsl source files - a custom shader language - into separate per-stage GLSL files targeting OpenGL 4.5 (#version 450 core).
Motivation
The primary motivation is to write vertex, fragment, geometry, and compute shaders in a single unified source file, sharing global declarations (structs, constants, uniforms, interface definitions) without duplication. AXSLC handles splitting the program into per-stage GLSL outputs and performs per-stage dead-code elimination on uniforms.
What AXSLC is not
AXSLC does not perform type checking. Type correctness is fully delegated to the downstream GLSL compiler (the OpenGL driver). AXSLC validates identifier resolution (undefined variables, unresolved symbols) but makes no attempt to infer or verify types.
Source File Extension
.axsl - Astralix Shader Language.
Output Files
For each stage present in the source, AXSLC writes a separate .glsl file. Stage-to-extension mapping:
| Stage | Output extension |
|---|---|
| vertex | .vert.glsl |
| fragment | .frag.glsl |
| geometry | .geom.glsl |
| compute | .comp.glsl |
Compilation Pipeline
AXSLC processes shaders through four distinct phases:
- Tokenizer - Lexical analysis, converts source text to token stream
- Parser - Syntax analysis using Pratt parsing, builds flat AST
- Linker - Resolves
@includefiles, validates identifiers, tracks uniform usage per stage - Emitter - Generates GLSL code for each stage with dead code elimination
Key Features
Unified Source Files
Write all shader stages in one file with shared global declarations. No more copy-pasting struct definitions between vertex and fragment shaders.
Example:
@version 450;
// Shared global struct - defined once
struct Material {
vec3 color;
float roughness;
};
uniform Material u_material;
interface Varyings {
vec2 v_uv;
vec3 v_normal;
};
@stage vertex {
in vec3 a_position;
out Varyings v;
void main() {
v.v_uv = a_position.xy;
v.v_normal = a_position;
gl_Position = vec4(a_position, 1.0);
}
}
@stage fragment {
in Varyings v;
out vec4 fragColor;
void main() {
// u_material only emitted in fragment stage (dead code elimination)
fragColor = vec4(u_material.color, 1.0);
}
}Dead Code Elimination
Global uniforms are only emitted in stages that actually reference them, preventing unused uniform warnings and reducing shader binary size.
Interface System
Define interface blocks once globally and reference them by name in stages. The compiler automatically expands and matches them between stages.
Include System
Use @include "path/to/file.axsl" to merge global declarations from other files, enabling modular shader libraries.
Annotations
Control GLSL layout qualifiers with annotations:
@location(N)- Interface field location@binding(N)- Uniform/buffer binding point@std430/@std140- Memory layout for buffers
Clean Output
Generates readable, properly formatted GLSL code with appropriate layout qualifiers and annotations.
Fast Compilation
No type checking means compilation is extremely fast. Type errors are caught by the downstream GLSL compiler where they belong.
Command Line Usage
axslc [options] <input.axsl>Options:
-o, --output <prefix>- Output file prefix (default:out)-I, --include-path <path>- Override base directory for includes-v, --verbose- Print compilation status-h, --help- Print usage--version- Print version
Output naming: <prefix>.vert.glsl, <prefix>.frag.glsl, etc.
Public API
For programmatic use, AXSLC provides a simple C++ API:
#include "compiler.h"
Compiler compiler;
CompileResult result = compiler.compile(source, "shader.axsl", "./");
if (!result.errors.empty()) {
// Handle errors
}
// result.stages is a map of StageKind → GLSL code
for (const auto& [stage, code] : result.stages) {
// Write or use the generated GLSL
}Limitations
AXSLC does not validate:
- Type errors or mismatches
- Missing main function
- Interface block mismatches between stages
- Circular includes (may cause infinite loop)
All type-level validation is delegated to the downstream GLSL compiler.