OpenGL 1.0 Graphics Simulation
A 3D scene simulation written from scratch in C++ and OpenGL 1.0 — no engine, no scene graph — with a day/night cycle, an 8-light system, waypoint path animation and a full Dear ImGui scene editor.
- Type
- University Assignment
- Module
- GDEV40026
- API
- OpenGL 1.0
- Window
- FreeGLUT
- Year
- 2025
- Team
- Solo
- Source Files
- 25 C++
- Resolution
- 1600×900
What is this?
A fully custom 3D scene simulation built from scratch in OpenGL 1.0 for the GDEV40026 Introduction to Graphics Programming module at Staffordshire University. No game engine. No scene graph. Every system — object loading, lighting, texturing, path animation, camera control, and the ImGui interface — written in C++ by hand.
The simulation runs at up to 240 FPS on a 1600×900 window and includes a real-time day/night cycle, a multi-light system with 8 independent light sources, per-object waypoint-based path animation, a full Dear ImGui editor interface, OBJ and MTL parsing, texture hotswapping via STB, and an in-simulation help menu. The window title reads: "3D OGL Simulation [Graphics Programming] | pls give me high marks :3".
// Final simulation — day scene, multi-light, full render
Development spanned six progress posts from 9 March to 8 May 2025 — each post building substantially on the last, from a spinning rectangle to a complete scene editor.
Watch on YouTube
// Full feature showcase — May 2025 submission
Video chapters: 00:00 Add Objects · 01:06 Transformation & Material Editing & Texture Hotswapping · 02:21 Scene Lighting · 05:21 Camera Controls · 06:25 Object Parenting & Animation · 10:39 Render Settings
Six Progress Posts
The forum thread documents six phases of development, each building on the last. Every post introduced new systems — from a spinning rectangle on day one to a fully editable 3D scene six weeks later.
-
Week 0 · 9 Mar 2025
Research & Project Pitch
- Explored OpenGL 1.0 fundamentals and pipeline documentation
- Defined the project scope: a day/night lighting simulation with loaded 3D models
- Set up the FreeGLUT + GLUT environment in Visual Studio
-
Post #1 · 10 Mar 2025
First 3D Scene & Lighting Foundations
- FreeGLUT window creation with 60 FPS timer loop
- Custom OBJ parser — vertices, normals, UV coordinates, face indices
- 3D cube with perspective projection, depth testing, back-face culling
- Smooth shading (GL_SMOOTH) with diffuse, ambient, and specular lighting
- On-Screen Display (OSD) text overlay using GLUT_BITMAP_9_BY_15 — FPS counter
-
Post #2 · 22 Mar 2025
Camera System & ImGui Foundation
- Mouse-driven camera — left click+drag to orbit/rotate, scroll to zoom
- WASD to move the selected object; Q/E to cycle objects in scene
- First Dear ImGui integration — render mode toggle, OSD toggle
- Colour-coded console logging with severity enum (Info / Warning / Error)
-
Post #3 · 30 Mar 2025
Full ImGui Interface & Texturing
- Object Properties panel — position, rotation, scale, uniform scaling toggle
- Scene Object Browser for listing and selecting objects
- Scene Hierarchy with parent/child object relationships — Grandparent → Parent → Child
isAncestorOf()check prevents cyclic parenting loops- STB-based texture loading — UV coordinate parsing and
glBindTextureintegration - Panel visibility managed through UIPanelStates;
glPushMatrix/glPopMatrixdebugging
-
Post #4 · 11 Apr 2025
Path Animation, Multi-Light & Day/Night Cycle
- Per-object waypoint path animation — Vector3 waypoints, loop toggle, path speed slider
- Animated path line rendering — visible debug arrows showing routes
- Day/night cycle — 30-second period via sin/cos; yellow sun line, purple moon line
- 8-light system — Sunlight, Moonlight + 6 additional configurable lights
- Selected object outline rendering; camera snap to object (F key), orbit mode (O key)
- Texture cache with mipmapping; correct UV wrapping for all loaded textures
- Modular UI panels via inheritance and polymorphism; lambdas for refactored rendering
-
Post #5 · 24 Apr 2025
Finalisation & Animator
- Animator tab inside Scene Hierarchy — path assignment per object, loop toggle
- Waypoints Editor — add/remove/reposition waypoints with live preview
- Flyout notification messages on key actions
- Help menu (Shift+H) — complete controls reference resizable popup
- Camera
directionFromAngles()— yaw/pitch to radians for correct forward movement - MTL material file parser — shininess, ambient, diffuse, specular from OBJ exports
-
Post #6 · 8 May 2025
Last-Minute Bug Fixes & Polish
- Fixed read access violation on multi-object deletion — parent/child ID handling corrected
- Scene Hierarchy search bar — ImGui text input to filter long object lists
- Frame rate limiter — auto-detects display refresh rate; set to 240 FPS target
- Wireframe mode now works correctly alongside object outline selection
- Spotlight added to each stacked torus; "deg" string used after degree sign encoding issue
- OSD text repositioned dynamically — no longer hardcoded to 800×600, works at any resolution
Dear ImGui Panels
Five floating ImGui panels form the entire scene editor. Each is resizable and independently togglable. The simulation runs underneath in real time while panels are open — no separate editor mode.
// Object properties + texture UI
Inspector
Panel
Scene Hierarchy & Animator
PanelScene Object Browser
PanelCamera Properties
PanelFull Keybinds
All controls are documented in-simulation via the Help & Keybinds popup (Shift+H). Some shortcuts require glutGetModifiers() to
detect Shift/Ctrl/Alt; others use ASCII codes for keys like -, =, and +.
| Key | Action |
|---|---|
W A S D | Move selected object |
Q / E | Previous / next object |
F | Snap camera to selected object |
O | Toggle orbit camera mode |
T | Toggle OSD text display |
H | Hide / show ImGui panels |
1 | Toggle wireframe mode |
- / + | Zoom out / zoom in |
Shift+A | Open Add Object popup |
Shift+H | Help & Keybinds popup |
Shift+R | Reset selected object transforms |
Ctrl+R | Reset camera position & rotation |
Del | Delete selected object |
ESC | Close open popups |
RMB+Drag | Orbit / rotate camera |
Scroll | Zoom camera in/out |
LMB+Drag↑ | Move camera forward/back |
LMB+Drag←→ | Rotate camera left/right |
Systems & Architecture
The project is built entirely in C++ without any game engine abstraction. Systems are organised into modular files — each class managing one concern. The main render loop runs via FreeGLUT's timer callback at the target frame interval.
// Debug path visualisation — animated waypoints
Object system
Object class parses OBJ files into vertex structures using helper functions split by
component — faces, normals, UVs each have their own parser method for clarity.Texturing
glTexImage2D. A
TextureManager caches loaded textures by filename to avoid redundant GPU uploads. Mipmapping is enabled for all textures. UV
coordinates are parsed per-vertex from OBJ files and applied with correct wrapping.Lighting
Path animation
Path class stores a vector of Vector3 waypoints. The PathManager tracks all paths in the scene. Each
object can be assigned a path from the Animator tab — the object interpolates between waypoints at the configured speed, looping if enabled. Paths
are visualised as debug lines in the scene.Code quality
directionFromAngles() — converts the camera's yaw and pitch to radians and applies trigonometry to return the correct forward
direction vector. Took a few hours to get right.Custom Source Files
25 custom C++ source and header files, plus the full Dear ImGui source, FreeGLUT, and STB libraries.
- Camera .cpp / .h
- Console .h
- Controls .cpp / .h
- DebugArrow .cpp / .h
- FrustumCulling .cpp / .h
- Main .cpp / .h
- Math .h
- Object .cpp / .h
- Path .h
- PathManager .cpp / .h
- Renderable .h
- Scene .cpp / .h
- TextureManager .cpp / .h
- UI .cpp / .h
- UIPanelBase .h
Challenges & Lessons
OpenGL 1.0's immediate mode is deceptively simple at the start and deceptively awkward once you push it. glPushMatrix and
glPopMatrix must be perfectly balanced — a missing pop left child objects multiplying their parent transform and flying off into the
void. Finding that took time.
The cyclic parenting bug was subtle: setting Object A as a child of Object B when B was already a child of A. The fix —
isAncestorOf() — walks the parent chain on every setParent call and rejects the operation if a cycle is detected.
Working without engine conveniences forces a deep understanding of what those conveniences actually do. Writing a UV parser, a texture cache, a path interpolator, and a scene hierarchy from scratch in a six-week academic sprint is not trivial — and the 85% grade reflects that it was done well.






