A comprehensive, hands-on tutorial for learning OpenGL 1.1 (fixed-function pipeline) using FreeGLUT. Each chapter includes detailed explanations and working code examples that you can compile and run.
While OpenGL 1.1 is considered legacy, it provides:
- An excellent foundation for understanding 3D graphics concepts
- Immediate results without complex shader programming
- Cross-platform compatibility with minimal dependencies
- A gentle learning curve for graphics programming beginners
Before starting, you'll need:
- Basic C programming knowledge
- A C compiler (GCC, Clang, or MSVC)
- OpenGL development headers
- FreeGLUT library
Each chapter is contained in its own directory with:
README.md- Chapter content and explanations- Source code files (
.cand.h) Makefile- Build instructions for Linux/macOSCMakeLists.txt- Cross-platform build configuration
- What You're Getting Into - Introduction to fixed-function vs. modern OpenGL
- Environment Setup - Installing dependencies and verifying your toolchain
- Project Skeleton - Basic project structure and build systems
- GLUT 101: Window + Main Loop - Creating windows and handling the main loop
- Drawing in Immediate Mode - First rendering with glBegin/glEnd
- Coordinate Systems & the Matrix Stacks - Understanding transformations
- Depth, Culling, and Viewport - Making 3D graphics work correctly
- Lighting and Materials - Classic Phong lighting model
- Textures in 1.1 - Loading and applying textures
- State You'll Use a Lot - Blending, fog, and other common states
- Display Lists - Optimizing static geometry
- Vertex Arrays - Better performance than immediate mode
- Input & Interaction with GLUT - Keyboard, mouse, and camera controls
- Text & UI Bits - Drawing text and 2D overlays
- Common Pitfalls - Debugging common issues
- Performance Tips for 1.1 - Optimization techniques
- Debugging & Introspection - Tools and techniques for debugging
- Cross-Platform Notes - Platform-specific considerations
- Packaging a Demo - Building distributable applications
- Exercises & Mini-Projects - Practice projects
- Where to Go Next - Transitioning to modern OpenGL
- 🎮 Final Project: Cosmic Defender - Complete 3D space shooter game!
Chapter 22 is a complete, playable 3D space shooter that demonstrates every technique from the tutorial:
- 3D rendering with lighting and materials
- Player movement and camera controls
- Enemy AI with pathfinding
- Projectile physics and collision detection
- Particle effects for explosions
- HUD with health, score, and game states
- Wave-based difficulty progression
Build and play:
cd chapter_22
make
./gameThis is your capstone project—a real game built with OpenGL 1.1!
Install dependencies:
# Ubuntu/Debian
sudo apt-get install build-essential libglu1-mesa-dev freeglut3-dev
# Fedora/RHEL
sudo dnf install gcc make mesa-libGLU-devel freeglut-devel
# macOS (note: OpenGL is deprecated but still works)
brew install freeglutBuild and run a chapter:
cd chapter_02_environment_setup
make
./demoInstall MinGW-w64 or use MSVC, then install FreeGLUT. Each chapter includes detailed build instructions.
Alternatively, use CMake for cross-platform builds:
cd chapter_XX
mkdir build && cd build
cmake ..
cmake --build .- Beginners: Follow chapters 1-7 in order
- Intermediate: Chapters 8-14 build on the basics
- Advanced: Chapters 15-21 cover optimization and best practices
- Final Project: Chapter 22 - Build a complete game!
Found a bug or want to improve an example? Pull requests are welcome!
This tutorial and all example code are released into the public domain (or MIT License where public domain is not applicable).
This tutorial is designed to teach OpenGL 1.1 concepts that remain relevant for understanding modern graphics programming, even though the API itself is considered legacy.
I wrote all of these in wsl2, using XWinrc and the following config that I run from my windows desktop:
<?xml version="1.0" encoding="UTF-8"?>
<XLaunch
WindowMode="MultiWindow"
ClientMode="NoClient"
LocalClient="False"
Display="0"
LocalProgram="xcalc"
RemoteProgram="xterm"
RemotePassword=""
PrivateKey=""
RemoteHost=""
RemoteUser=""
XDMCPHost=""
XDMCPBroadcast="False"
XDMCPIndirect="False"
Clipboard="True"
ClipboardPrimary="True"
ExtraParams=""
Wgl="True"
DisableAC="True"
XDMCPTerminate="False"
/>Then, in my .bashrc, I added:
export DISPLAY=$(ip route list default | awk '{print $3}'):0Some have recommended export LIBGL_ALWAYS_INDIRECT=1, but I would highly
advise against it - I cannot get things to run with a decent framerate if I
enable this setting.