Hypergiant
An OpenGL-based game library for CHICKEN Scheme
Install / Use
/learn @AlexCharlton/HypergiantREADME
Hypergiant
Hypergiant is an OpenGL-based library for games and other interactive media applications written in CHICKEN Scheme. Its philosophy is that it should be easy to efficiently perform common operations, but it shouldn’t be hard to do anything else. Hypergiant is therefore not a framework or an engine, and doesn’t force you into any one mode of operation. Rather it’s role is to act as a glue between other graphics libraries.
The goal of Hypergiant is to make it as easy to perform simple tasks as something like LÖVE 2D or CHICKEN’s own doodle (except with Hypergiant, working in 3D is just as easy as working in 2D), while keeping the full power of OpenGL available – essentially making it possible to go from prototype to polished project with the same library.
Hypergiant should run on anything that supports OpenGL (including ES).
Note that this is an early release of Hypergiant. Some features that you might expect are missing, but there is more to come. Feel free to pass feature requests my way, though. Or better yet: patches!
Installation
This repository is a Chicken Scheme egg.
It is part of the Chicken egg index and can be installed with chicken-install hypergiant.
Requirements
- opengl-glew
- glfw3
- gl-utils
- gl-math
- gl-type
- glls
- Hyperscene
- noise
- soil
- random-bsd
- miscmacros
- srfi-42
- srfi-99
While Hypergiant doesn’t require any external libraries directly, opengl-glew and glfw3 depend on OpenGL, GLEW, GLFW (the most recent major version is required: 3.X). gl-type depends on Freetype
When installing GLFW on OS X through Homebrew, an extra step is needed. Homebrew renames the library’s from the default. You can fix this by creating a link that points to the library that gets installed. E.g. sudo ln -s <homebrew-lib-dir>/glfw3.dylib /usr/local/lib/libglfw.dylib
Documentation
Hypergiant is a largely a glue library, intending to make the creation of real-time graphical applications easier. The main tasks that it supports are:
- Window opening and initialization, including a main loop
- Hypergiant acts as a glue between Hyperscene and glls. These two libraries were designed to work well together, making it possible to render an entire application in pure C, despite using Scheme to define the bulk of (if not all of) the rendering tasks. Hypergiant removes the boiler-plate required to use these libraries together.
- Intuitive control of input events, namely mouse and keyboard events (joystick support to come)
- Creation of geometric primitives as well as animated sprites
- IQM model loading and animation
- A particle system
- Simple shaders to make simple visualization easy
Hypergiant reexports (and uses) the following libraries:
- opengl-glew (prefix
gl:): Bindings to core OpenGL or OpenGL ES - glls (some macros modified, as noted below): Creates OpenGL Shader Language shaders in Scheme, and compiles rendering functions in C for use with the shaders
- Hyperscene (some functions modified, as noted below): Scene management with a scene-graph, cameras, frustum culling, and a lighting extension (extensible only in C)
- gl-utils (gl-utils-core is prefixed with
gl:, all other modules have no prefix): Extends OpenGL to help make common operations easier - gl-math: Provides fast matrix, quaternion, and vector manipulation functions, suitable for use with OpenGL
- gl-type: Loads Truetype fonts and renders them as OpenGL objects
- soil: Image loading for OpenGL
- noise: Noise functions that run on the GPU, created as glls shaders
Because Hypergiant reexports from all of these eggs, when the import list of one of these eggs changes, Hypergiant must be reinstalled in order to reflect the change. You can use the following command to ensure that a full update is performed:
chicken-install opengl-glew glfw3 gl-utils gl-math glls hyperscene gl-type soil noise hypergiant
Take care with using any of the functions from these libraries that aren’t exported by Hypergiant (including glfw3). This probably means that you need to understand how those functions will interact with Hypergiant before you use them.
Running Hypergiant applications
Hypergiant is designed to work either compiled or interpreted.
When interpreted with csi, Hypergiant frees up the REPL so that commands can still be entered, allowing for live-coding. This is reported to not work when the readline egg is active, although it works fine with parley.
When compiling Hypergiant, csc FILE.scm is usually sufficient, unless a pipeline has been defined (with define-pipeline). In this case, linking to OpenGL is needed:
- On Linux:
csc -lGL FILE.scm - On OS X:
csc -framework OpenGL FILE.scm - On Windows:
csc -lopengl32 FILE.scm
Hypergiant is designed to work by default with OpenGL 3.3 and GLSL version 330 (and version 2 and 120, respectively for OpenGL ES). This is a relatively old standard, and even older hardware should have drivers available that support this. You can still use any versions you want by passing context-version arguments to start, although the pre-defined pipelines and shaders are stuck at their current versions for now. If you have any issues with this, let me know and we can try to work something out.
Main loop and window
[procedure] (start WIDTH HEIGHT TITLE [init: INIT] [update: UPDATE] [pre-render: PRE-RENDER] [post-render: POST-RENDER] [cleanup: CLEANUP] . WINDOW-HINTS)
Start the main body of the program, creating a new window with dimensions WIDTH and HEIGHT, and the given TITLE. INIT may be a function of zero arguments that will be called during the initialization sequence, after all libraries are initialized, but before the main loop. UPDATE may be a function of one argument (delta: the time that passed between the current update and the last one) that is called once per frame before scenes are updated and rendered. PRE-RENDER and POST-RENDER may be functions of zero arguments that perform some action immediately before and after render-cameras is called, respectively. CLEANUP may be a function of zero arguments which is called before the window is closed. WINDOW-HINTS accepts the same keyword arguments as make-window.
[procedure] (stop)
Ends the main loop and closes the windowing, triggering any cleanup that was passed to start.
[procedure] (get-window-size)
Return the size of the window as two values: width and height.
[procedure] (get-framebuffer-size)
Return the size of the framebufffer as two values: width and height.
[procedure] (get-time)
Return the time, in seconds, that has elapsed since start was called.
[procedure] (frame-rate)
Return the current frame-rate, averaged over a number of frames. If rendering the frame rate, consider using update-string-mesh!.
[procedure] (get-window-position)
Returns the (X Y) position (as values) of the upper left corner of the window, in screen coordinates.
[procedure] (set-window-position X Y)
Sets the position of the upper left corner of the window, to (X Y) in screen coordinates.
[procedure] (get-clipboard-string)
Returns the contents of the clipboard.
[procedure] (set-clipboard-string STRING)
Sets the contents of the clipboard to STRING.
Input
Input is managed by bindings: sets of keys and the actions that they are supposed to trigger. Different input methods use separate stacks for tracking which bindings are current. Bindings are represented as lists of binding records.
Most standard English keyboard keys are named after a code that looks like +key-***+. Alpha and numeric keys are named based on their character, such as +key-a+ and +key-1+, with special keys being named based on the following descriptors (e.g. +key-up+): up, down, left, right, delete, space, backspace, tab, enter, escape, slash, backslash, period, comma, apostrophe, minus, equal, semicolon, grave-accent, right-bracket, left-bracket, insert, end, home, page-down, page-up, right-super, right-alt, right-control, right-shift, left-super, left-alt, left-control, left-shift, pause, print-screen, num-lock, scroll-lock, caps-lock, last, menu, world-2, and world-1. F keys f1 through f25 are defined, as are keypad keys kp-0 through kp-9, kp-equal, kp-enter, kp-add, kp-subtract, kp-multiply, kp-divide, and kp-decimal.
Mouse buttons +mouse-button-middle+, +mouse-button-right+, +mouse-button-left+, +mouse-button-last+, and +mouse-button-1+ through +mouse-button-8+ are also defined.
[record] (binding)
The mostly-opaque binding record, which can be created with make-binding or make-bindings. List of binding records, are collectively referred to as bindings.
[procedure] (make-binding ID KEY [scancode?: SCANCODE?] [mods: MODS] [press: PRESS] [release: RELEASE] [toggle: TOGGLE] [reverse-toggle: REVERSE-TOGGLE])
Create a binding with the identifier ID for the key (or button) KEY. ID may be any sort of object that can be compared with equal?, that should be unique for a collection of bindings. SCANCODE? is a boolean (defaulting to #f) that indicates whether KEY is a scancode or not (a scancode is a system+hardware-specific integer that corresponds to a particular key). MODS is a list of modifiers that must be held at the same time as the KEY for the action to take place, and may be a list containing any or all of `
