CmdlineGL - Interpreter for subset of OpenGL 1.4 API
CmdlineGL [OPTIONS] <opengl_commands >user_events
# Play some recorded 3D graphics
bzcat graphics.txt.bz2 | CmdlineGL >/dev/null
# Experiment from Bash
source CmdlineGL.lib
glClearColor '#00FF00'
glClear GL_COLOR_BUFFER_BIT
cglSwapBuffers
CmdlineGL is an interpreter for parsing and executing OpenGL functions, which also simplifies the OpenGL API in several ways to make it more user-friendly. It comes with shell bindings for bash, allowing for experiments right from the terminal (if you have a graphical desktop). It only covers the functions a beginner would need, and doesn't aspire to anything newer than the 1.4 API. It also provides some basic access to the GLU, SDL_image (loading image files), and FTGL (font rendering) libraries, for the ability to make useful demos that the raw OpenGL API can't provide on its own.
Terminate after a zero-length read (EOF)
Don't automatically reinitialize glViewport after the window has changed size. This allows the application to control the viewport area.
Don't automatically set up a projection matrix or rescale it after the window changes size.
Create a named pipe at this path, and read from it. This option is not available on Windows.
Using Unix X11 notation, specify the window geometry. Negative X and Y are not yet supported.
Set the title of the window.
Don't report user input activity on stdout. (other messages and events will still be printed)
Dump a list of all available commands on stdout.
Dump a list of all symbolic constants on stdout. These constants may be given to any command which takes an integer argument.
Print the version and exit.
Print a brief usage summary
All commands take parameters separated by whitespace, in much the same way as a shell would break its arguments. There is also a quoting mechanism that may be used for any type of parameter. If the parameter begins with '
or "
, then whitespace (other than newlines) will be included in the parameter until the matching quote character. Literal newline characters always end the command. Within the string, \n
will be converted to newline charachers, and any other character preceeded by a backslash will be included as-is, allowing you to escape the quote character and the backslash.
All integer parameters of commands may be given as decimal, hexidecimal or symbolic GL_
constants. If an integer parameter does not begin with a digit, CmdlineGL will look it up in the table of symbolic codes, and if it is not found, the command will fail and not execute.
All floating point values may be specified as a normal decimal notation. However, to make things easier for Bash scripts, they may also contain a divisor, like "34/100". To facilitate fixed-point math on lots of parameters, CmdlineGL supports a feature of a "default divisor" that will be applied to EVERY floating point parameter of every command, unless the parameter contains a divisor already. See cglPushDivisor
below.
Many OpenGL commands take a color parameter, usually as 3 or 4 floating point numbers in the range [0..1]. In each case, you may supply a single HTML-style hex code like '#RRGGBB' or '#RRGGBBAA' in their place. The floating point values ARE affected by any implied divisor in effect (see above) but the HTML color codes are NOT.
All future floating-point numbers receive this implied "/DIVISOR". This does not replace a divisor that is manually specified.
For example,
cglPushDivisor 100
glRotate 12/1 100 100 100
becomes
glRotated(12, 1, 1, 1);
Clear the current default divisor, returning to whatever default was set before that. The initial default is 1.
These commands control CmdlineGL itself, and assist with setting up a render loop.
Repeat a string of text on stdout (may be confused for user input events, but maybe that's what you want)
Cause CmdlineGL to terminate (with error code 0)
Alias for cglExit
Return the number of milliseconds since start of the program.
Sleep for a number of milliseconds from when the command is received
Sleep until the specified time, measured as milliseconds from start of program.
Swap front and back buffer, showing the frame you were drawing and beginning a new frame. (you still need to call glClear yourself) If a window resize is pending, it will be performed at this point.
Clear one or more aspects of the frame buffer. Normally the constants are combined as a bit mask, but for this protocol they are just given as multiple arguments.
Specify what color to use when clearing the frame buffer. You may use a single HTML-style color code, or individual floating point components. See "Colors"
Select what depth to assign when clearing the depth buffer.
Push any un-written commands through to the graphics layer.
Enable one or more GL feature bits.
Disable one or more GL feature bits.
Adjust GL optional behavior.
Control how new pixel colors are blended into the existing frame buffer. SOURCE_FACTOR and DEST_FACTOR each an enum constant describing the equation used.
Control whether lighting is calculated per-pixel or per-vertex.
These settings affect the overall lighting calculation
Set one or both faces of polygons to use the current color as one or more color components of the "material" in the lighting equation. FACE is: GL_FRONT, GL_BACK, GL_FRONT_AND_BACK, and MODE is: GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_AMBIENT_AND_DIFFUSE.
Apply a fog setting. PNAME selects which value to change, and PARAMS depends on PNAME. If PNAME is a color, you may use HTML color notation. See "Colors".
Apply a lighting setting. PNAME is the setting to change, and PARAMS depend on PNAME. If the PARAMS are a color, you may use HTML color notation. See "Colors".
Apply a per-light setting. LIGHT is the enum or number of the light to be altered, and PNAME selects which parameter to change. PARAMS depends on PNAME. If PARAMS is a color, you may use HTML color notation. See "Colors".
Begin plotting points of geometry type MODE.
Stop plotting points.
Plot a vertex at (X,Y), (X,Y,Z), or (X,Y,Z,W)
Specify the Normal vector for the next Vertex.
Specify texture coordinates to use for the next Vertex.
Specify a color value to be used in the calculation of the color for the next vertex. The color may be specified in HTML notation or as separate components. See "Colors".
Apply a Material property that affects how future vertices will be affected by various lighting parameters. See OpenGL documentation for details, but FACE and PNAME should be symbolic constants, and PARAMS depends on PNAME. If PARAMS are a color, you may use HTML notation. See "Colors".
Select the current texture object for purpose TARGET. (TARGET is usually GL_TEXTURE_2D)
Change an attribute of the texture object currently bount to TARGET. PNAME is the name of the attribute, and PARAMS depend on PNAME. If PARAMS is a color, you may use HTML hex notation; see "Colors".
Load image data into the texture currently bound to GL_TEXTURE_2D. If compiled with support for the SDL_image library, you may supply any image format handled by that library, else you are limited to Windows Bitmaps ".BMP". The image must contain RGB or RGBA pixels.
Select which matrix stack will be affected by future matrix commands.
Save a copy of the current matrix onto the current matrix stack.
Restore the previous saved matrix.
Overwrite the current matrix with a matrix that has no effect on vertices.
Directly overwrite the matrix with 16 values.
Multiply the current matrix by this specified matrix
When given one argument, scale the X, Y, and Z axis by the specified value. When given two arguments, scale X and Y, leaving Z unchanged. When given three arguments,scale X, Y, and Z.
Apply a translation to the matrix. The Z coordinate is optional and defaults to 0.
Rotate DEGREES around the axis defined by (X,Y,Z)
Change the current matrix to "look at" CENTER from EYE.
Define the 2D region of the screen to be rendered by the current matrix.
Set up a projection matrix that maps the given coordinate values to the edges of the viewport, and sets the near and far clipping plane.
Set up a projection matrix where the given coordinates are the edges of the screen at the near clipping plane, and scale proportionally as the Z coordinate gets farther from the near plane.
Begin recording a new display list, either creating or overwriting LISTNAME. MODE can either be GL_COMPILE or GL_COMPILE_AND_EXECUTE. LISTNAME can be any string of text and is not limited to OpenGL's integer "names".
End the recording.
Replay a recorded list.
Quadric objects must be created before they can be used.
Set the DRAW style of the NAMEd quadric: GLU_FILL, GLU_LINE, GLU_SILHOUETTE, GLU_POINT
Set the type of NORMALs to calculate when using the NAMEd quadric: GLU_NONE, GLU_FLAT, GLU_SMOOTH
Set the in/out ORIENTATION of polygons when using the NAMEd quadric: GLU_OUTSIDE, GLU_INSIDE
Set whether or not to generate texture coordinates when drawing with the NAMEd quadric: GLU_TRUE, GLU_FALSE
Draw a cylinder (or cone) with BASE radius at z=0 and TOP radius at z=height, traveling HEIGHT distance on the Z axis, composed of n=SLICES polygons radially around the body and n=STACKS polygons along the height. NAME selects a set of quadric parameters for the polygons.
Draw a sphere of RADIUS around the origin, composed of n=SLICES polygons radially around the Z axis and n=STACKS polygons along the z axis.
Draw a flat disk (inner = 0
) or donought (<inner
0>>) around the Z axis with the given OUTER radius and INNER radius, composed of SLICES polygons radially around Z and LOOPS concentric rings.
Same as above, but only from START degrees around Z axis until and SWEEP degrees afterward.
These functions come from the FTGL library. They can open any font file that the FreeType library can open. A symbolic name takes the place of FTGL's FTfont*
pointer. You must call one of the Create methods (and it must succeed) to initialize a symbolic name before it can be used in any of the rendering functions.
Create a 2-color font that renders directly to the framebuffer in 2D.
Create a 256-color-grayscale font that renders directly to the framebuffer in 2D.
Create a font that renders each glyph into a texture, so that a small set of textures can supply all your rendering needs.
Create a texture-based font that renders each line of text into its own texture, so that common phrases can be drawn as a single polygon.
Create 3D models to represent each glyph extruded as a solid object.
Create 2D model of GL lines that trace the outline of each glyph.
Create each glyph as a flat 2D mesh of polygons.
Free resources and un-define the symbolic NAME.
Set the charmap to one of the codes known by the FreeType library.
For texture and raster fonts, render each glyph at SIZE pixels. For Vector fonts, render each glyph at SIZE logical units.
For extruded fonts, set the depth to SIZE units.
For extruded fonts.
Renter TEXT using NAMEd font, affected by FLAGS. In the C API, the flags are combined, but in this command each flag is given as another parameter. Flags are: FTGL_RENDER_FRONT, FTGL_RENDER_BACK, FTGL_RENDER_SIDE, FTGL_RENDER_ALL, FTGL_ALIGN_LEFT, FTGL_ALIGN_RIGHT, FTGL_ALIGN_CENTER, FTGL_ALIGN_JUSTIFY.
The typical render loop, taking advantage of CmdlineGL's ability to synchronize frames to a clock, looks like this:
read output of CmdlineGL until "t=" event indicating current timestamp
clear frame buffer
render OpenGL graphics
call glFlush and cglSwapBuffers to show the rendering
call cglSync telling it to delay until T + framerate_period
call cglGetTime, so that new timestamp will be available immediately after sleep
repeat
There are many examples in the ./share/examples
directory that ships with this project, though you may or may not have them installed. Reproduced below, SpinText.sh is a minimal example of something visually interesting. It requires variables $font
(a path to a .ttf font file) and $text
(the text to render).
spin_rate=70 # Degree per second
R=0 # current rotation
T=0 # "game-time", in milliseconds
# Initialize CmdlineGL for rendering only (no input or feedback)
source CmdlineGL.lib
CmdlineGL_Start ro
glEnable GL_NORMALIZE GL_DEPTH_TEST GL_CULL_FACE
glShadeModel GL_SMOOTH
# Load font file and configure font rendering parameters
ftglCreateExtrudeFont font1 "$font"
ftglSetFontFaceSize font1 72 72
ftglSetFontDepth font1 20
# Prepare the graphics in a display list. Need to call once first since
# ftgl creates its own display lists, then again to capture those in the
# second display list.
ftglRenderFont font1 "$text" FTGL_ALIGN_CENTER FTGL_RENDER_ALL
glNewList mytext GL_COMPILE
glTranslate -$(( ${#text}/2 * 40 )) -36 10 # flaky guess at string mid
ftglRenderFont font1 "$text" FTGL_RENDER_ALL
glEndList
# set up lighting (otherwise no change as it rotates)
glEnable GL_LIGHTING GL_LIGHT0
glLight GL_LIGHT0 GL_AMBIENT .8 .8 .8 0
glLight GL_LIGHT0 GL_DIFFUSE 1 .8 .8 0
glLight GL_LIGHT0 GL_SPECULAR .8 .8 .8 0
glLight GL_LIGHT0 GL_POSITION 10 10 10 1
while true; do
glClear GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT
glLoadIdentity
glRotate $((R+=spin_rate))/60 0 1 0 # assuming 60fps
glScale 10/$((40 * ${#text} / 2)) # flaky guess at window width
glCallList mytext
glFlush
cglSwapBuffers
cglSync $((T+=16)) # blindly assume we can maintain 60fps
done
More advanced timing and handling of user input can be seen in ModelViewer.sh, usage of Quadrics for quick rendering of solids can be seen in Robot.sh, and direct manipulation of the modelview matrix as a coordinate system can be seen in FlightSim.sh
Please report bugs in the issue tracker at http://github.com/nrdvana/CmdlineGL