source: project/wiki/eggref/4/hypergiant @ 33296

Last change on this file since 33296 was 33296, checked in by acharlton, 4 years ago

wiki/hypergiant: Fix typo

File size: 61.0 KB
Line 
1== Hypergiant
2[[toc:]]
3Hypergiant 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.
4
5The 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.
6
7Hypergiant should run on anything that supports OpenGL (including ES).
8
9Note 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!
10
11
12=== Requirements
13* opengl-glew
14* glfw3
15* gl-utils
16* gl-math
17* gl-type
18* glls
19* Hyperscene
20* noise
21* soil
22* random-mtzig
23* miscmacros
24* srfi-42
25* srfi-99
26
27While Hypergiant doesn’t require any external libraries directly, opengl-glew and glfw3 depend on OpenGL, [[http://glew.sourceforge.net/|GLEW]], [[http://www.glfw.org/|GLFW]] (the most recent major version is required: 3.X). gl-type depends on [[http://www.freetype.org/|Freetype]]
28
29When 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}}
30
31
32=== Documentation
33Hypergiant is a largely a glue library, intending to make the creation of real-time graphical applications easier. The main tasks that it supports are:
34
35* Window opening and initialization, including a main loop
36* 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.
37* Intuitive control of input events, namely mouse and keyboard events (joystick support to come)
38* Creation of geometric primitives as well as animated sprites
39* [[http://sauerbraten.org/iqm/|IQM]] model loading and animation
40* A particle system
41* Simple shaders to make simple visualization easy
42
43Hypergiant reexports (and uses) the following libraries:
44
45* [[http://wiki.call-cc.org/eggref/4/opengl-glew|opengl-glew]] (prefix {{gl:}}): Bindings to core OpenGL or OpenGL ES
46* [[http://wiki.call-cc.org/eggref/4/glls|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
47* [[http://wiki.call-cc.org/eggref/4/hyperscene|Hyperscene]] (some functions modified, as noted below): Scene management with a scene-graph, cameras, frustum culling, and a lighting extension (extensible only in C)
48* [[http://wiki.call-cc.org/eggref/4/gl-utils|gl-utils]] (gl-utils-core is prefixed with {{gl:}}, all other modules have no prefix): Extends OpenGL to help make common operations easier
49* [[http://wiki.call-cc.org/eggref/4/gl-math|gl-math]]: Provides fast matrix, quaternion, and vector manipulation functions, suitable for use with OpenGL
50* [[http://wiki.call-cc.org/eggref/4/gl-type|gl-type]]: Loads Truetype fonts and renders them as OpenGL objects
51* [[http://wiki.call-cc.org/eggref/4/soil|soil]]: Image loading for OpenGL
52* [[http://wiki.call-cc.org/eggref/4/noise|noise]]: Noise functions that run on the GPU, created as glls shaders
53
54Because 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:
55
56    chicken-install opengl-glew glfw3 gl-utils gl-math glls hyperscene gl-type soil noise hypergiant
57
58Take 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.
59
60
61==== Running Hypergiant applications
62Hypergiant is designed to work either compiled or interpreted.
63
64When 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.
65
66When 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:
67
68* On Linux: {{csc -lGL FILE.scm}}
69* On OS X: {{csc -framework OpenGL FILE.scm}}
70* On Windows: {{csc -lopengl32 FILE.scm}}
71
72Hypergiant 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.
73
74
75==== Main loop and window
76<procedure> (start WIDTH HEIGHT TITLE [init: INIT] [update: UPDATE] [pre-render: PRE-RENDER] [post-render: POST-RENDER] [cleanup: CLEANUP] . WINDOW-HINTS)</procedure>
77
78Start 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 [[http://api.call-cc.org/doc/glfw3/make-window|{{make-window}}]].
79
80<procedure> (stop)</procedure>
81
82Ends the main loop and closes the windowing, triggering any cleanup that was passed to {{start}}.
83
84<procedure> (get-window-size)</procedure>
85
86Return the size of the window as two values: width and height.
87
88<procedure> (get-framebuffer-size)</procedure>
89
90Return the size of the framebufffer as two values: width and height.
91
92<procedure> (get-time)</procedure>
93
94Return the time, in seconds, that has elapsed since {{start}} was called.
95
96<procedure> (frame-rate)</procedure>
97
98Return the current frame-rate, averaged over a number of frames. If rendering the frame rate, consider using {{update-string-mesh!}}.
99
100<procedure> (get-window-position)</procedure>
101
102Returns the {{(X Y)}} position (as values) of the upper left corner of the window, in screen coordinates.
103
104<procedure> (set-window-position X Y)</procedure>
105
106Sets the position of the upper left corner of the window, to {{(X Y)}} in screen coordinates.
107
108<procedure> (get-clipboard-string)</procedure>
109
110Returns the contents of the clipboard.
111
112<procedure> (set-clipboard-string STRING)</procedure>
113
114Sets the contents of the clipboard to {{STRING}}.
115
116
117==== Input
118Input 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.
119
120Most 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.
121
122Mouse buttons {{+mouse-button-middle+}}, {{+mouse-button-right+}}, {{+mouse-button-left+}}, {{+mouse-button-last+}}, and {{+mouse-button-1+}} through {{+mouse-button-8+}} are also defined.
123
124<record> (binding)</record>
125
126The mostly-opaque binding record, which can be created with {{make-binding}} or {{make-bindings}}. List of {{binding}} records, are collectively referred to as ''bindings''.
127
128<procedure> (make-binding ID KEY [scancode?: SCANCODE?] [mods: MODS] [press: PRESS] [release: RELEASE] [toggle: TOGGLE] [reverse-toggle: REVERSE-TOGGLE])</procedure>
129
130Create 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 {{+mod-super+}}, {{+mod-alt+}}, {{+mod-control+}}, and {{+mod-shift+}}. {{PRESS}} is a zero element function that is activated on a press event. {{RELEASE}} is a zero element function that is activated on a release event. {{TOGGLE}} and {{REVERSE-TOGGLE}} expect a parameter that must be an integer. {{TOGGLE}} indicates that when the key (plus mods) is pressed, the parameter should be incremented, and decremented when released. {{REVERSE-TOGGLE}} indicates the opposite. If {{TOGGLE}} or {{REVERSE-TOGGLE}} are specified, {{PRESS}} and {{RELEASE}} will be ignored, and only one of {{TOGGLE}} or {{REVERSE-TOGGLE}} may be used for a binding.
131
132{{TOGGLE}} and {{REVERSE-TOGGLE}} are useful when two keys are used to perform a continuous action (that may be negated). The game’s update loop should check the parameter passed to the toggle binding to see what action should be performed. For instance, if a parameter {{move}} is defined as {{0}}, and set as a toggle when the right key is pressed and reverse-toggle when the left key is pressed, the movement of a character for a given frame can be determined by multiplying {{(move)}} by the character’s movement speed.
133
134<procedure> (binding? X)</procedure>
135
136Return true when passed a binding record.
137
138<procedure> (binding-id BINDING)</procedure>
139
140Return the value of the {{ID}} of the given binding.
141
142<procedure> (make-bindings BINDING-LIST)</procedure>
143
144Create a list of bindings. {{BINDING-LIST}} should be a list of {{(ID KEY [scancode?: SCANCODE?] [mods: MODS] [press: PRESS] [release: RELEASE] [toggle: TOGGLE] [reverse-toggle: REVERSE-TOGGLE])}} lists. These lists should be {{apply}}-able to {{make-binding}}.
145
146<procedure> (add-binding BINDINGS BINDING)</procedure>
147
148Non-destructively modify the list {{BINDINGS}} with the new binding. {{BINDING}} should be a list that is {{apply}}-able to {{make-binding}}.
149
150<procedure> (get-binding BINDINGS ID)</procedure>
151
152Return the binding with the given {{ID}} from the list of {{BINDINGS}}.
153
154<procedure> (remove-binding BINDINGS ID)</procedure>
155
156Non-destructively modify the list {{BINDINGS}}, removing the binding with the given {{ID}}.
157
158<procedure> (change-binding BINDINGS ID BINDING)</procedure>
159
160Non-destructively modify the list {{BINDINGS}}, replacing the binding with the given {{ID}} with the new binding. {{BINDING}} should be a list that is {{apply}}-able to {{make-binding}}.
161
162
163===== Key bindings
164<procedure> (push-key-bindings BINDINGS)</procedure>
165
166Set the currently active action that will be triggered when a key is pressed, pushing that action onto a stack. {{BINDINGS}} may be a list of bindings, in which case those bindings will be obeyed. {{BINDINGS}} may also be a function of four arguments – {{(key scancode action mods)}} – in which case this function is called when a key press occurs. {{key}} is a key code, whereas {{scancode}} is the corresponding scancode for the key that was pressed. {{action}} is one of {{+press+}}, {{+release+}}, or {{+repeat+}}, and {{mods}} is the integer formed by anding together the modifier keys – {{+mod-super+}}, {{+mod-alt+}}, {{+mod-control+}}, and {{+mod-shift+}} – that were pressed at the time of the key event.
167
168<procedure> (pop-key-bindings)</procedure>
169
170Return the state of the key bindings to before the last {{push-key-bindings}}.
171
172<parameter> (char-callback)</parameter>
173
174This parameter may be set to be a one argument function that is called whenever a unicode character is generated. The function will be called with an integer representing the character. Use this rather than relying on key codes when text input is desired. Note that it is often desirable to have some form of key bindings present even when the char-callback function is set (e.g. pressing escape may exit a text field), but if no other key bindings are desired, an empty list may be passed to {{push-key-bindings}}.
175
176
177===== Mouse bindings
178<procedure> (push-mouse-bindings BINDINGS)</procedure>
179
180Set the currently active bindings that will be referenced when a mouse button is pressed, pushing those bindings onto a stack. {{BINDINGS}} must be a list of bindings.
181
182<procedure> (pop-mouse-bindings)</procedure>
183
184Return the state of the mouse bindings to before the last {{push-mouse-bindings}}.
185
186
187===== Cursor and scrolling
188<procedure> (get-cursor-position)</procedure>
189
190Return the {{(x y)}} coordinates of the cursor as values, in pixels, relative to the upper-left of the window (down is the direction of positive Y).
191
192<procedure> (set-cursor-position X Y)</procedure>
193
194Set the position of the cursor on the window to {{(X Y)}}, in pixels, relative to the upper-left of the window (down is the direction of positive Y).
195
196<procedure> (get-cursor-world-position CAMERA)</procedure>
197
198Returns two values: the near and far coordinates ( {{(x y z)}} three-element f32vectors) representing the cursor position projected onto the near and far planes of the {{current-camera-view-projection}} of {{CAMERA}} (see [[#scenes|Scenes]]).
199
200<parameter> (cursor-movement-callback)</parameter>
201
202A parameter that may be set to a two argument function, which is called when the cursor is moved. The two arguments for the function represent the new x and y coordinates of the cursor, in pixels, relative to the upper-left of the window (down is the direction of positive Y).
203
204<parameter> (scroll-callback)</parameter>
205
206A parameter that may be set to a two argument function, which is called when the mouse wheel or track-pad is scrolled. The two arguments for the function represent the x and y distance (in pixels) that has been scrolled, respectively.
207
208
209==== Scenes
210Hypergiant reexports most of [[http://wiki.call-cc.org/eggref/4/hyperscene|Hyperscene]] except for {{resize-cameras}}, since it manages this functionality. {{resize-cameras}} is handled by {{start}}. {{add-node}}, {{add-light}}, {{make-camera}}, and {{set-max-lights!}} are modified as described below.
211
212Cameras are automatically resized in Hypergiant so that their projection matrix matches the bounds of the window.
213
214<constant> ui</constant>
215
216A Hyperscene scene that has one orthographic camera, included for UI elements. The camera is always sized to the window and positioned such that its upper left corner is {{(0 0)}}. The UI scene’s camera is always rendered last.
217
218<parameter> resize-hooks</parameter>
219
220A parameter that contains a list of functions of two arguments, width and height, that are called every time the window is resized.
221
222<procedure> (make-camera TYPE STYLE SCENE [near: NEAR] [far: FAR] [angle: ANGLE] [width: WIDTH] [height: HEIGHT] [viewport-width-ratio: VIEWPORT-WIDTH-RATIO] [viewport-height-ratio: VIEWPORT-HEIGHT-RATIO] [static-viewport?: STATIC-VIEWPORT?])</procedure>
223
224Identical to Hyperscene’s {{make-camera}}, except {{WIDTH}} and {{HEIGHT}} default to the window’s dimensions.
225
226Create a new camera associated with the given scene. {{TYPE}} must be one of {{#:ortho}} or {{#:perspective}} for an orthographic or a perspective camera, respectively. {{STYLE}} must be one of {{#:position}}, {{#:look-at}}, {{#:orbit}}, or {{#:first-person}}. New cameras are automatically activated. {{NEAR}} is the near plane of the camera, defaulting to {{1}}. {{FAR}} is the far plane of the camera, defaulting to {{10000}}. {{ANGLE}} is the view-angle, in degrees, for perspective cameras, defaulting to {{70}}. {{WIDTH}} and {{HEIGHT}} should be initialized to the size of camera’s viewport. {{VIEWPORT-WIDTH-RATIO}} and {{VIEWPORT-HEIGHT-RATIO}} scale the camera’s viewport (its view frustum’s near plane) in the width and height direction. The effects of the scaling persist after {{resize-cameras}} is called. If {{STATIC-VIEWPORT?}} is {{#t}}, the camera’s viewport dimensions will be fixed such that they won’t be changed by {{resize-cameras}}, although {{VIEWPORT-WIDTH-RATIO}} and {{VIEWPORT-HEIGHT-RATIO}} still effect the final viewport size.
227
228<procedure> (add-light PARENT COLOR INTENSITY [direction: direction] [spot-angle: SPOT-ANGLE] [position: POSITION] [radius: RADIUS])</procedure>
229
230As in Hyperscene, adds a new light to the given {{PARENT}} node (or scene) with {{#f32(r g b)}} {{COLOR}}. {{INTENSITY}} is the floating point value associated with the brightness of the light. {{DIRECTION}} is an {{#f32(x y z)}} vector that indicates the direction that the light is pointing, defaulting to {{#f32(0 0 0)}}. {{SPOT-ANGLE}} indicates the angle in radians that the light is spread over (defaulting to {{0}}, representing a non-spotlight source). A node is returned that can be moved, rotated, and sized like any other node.
231
232This function is extended with {{POSITION}}, which sets the initial position of the light, and {{RADIUS}}, which sets the radius of the light’s bounding sphere.
233
234<procedure> (add-node PARENT PIPELINE [mesh: MESH] [vao: VAO] [mode: MODE] [n-elements: N-ELEMENTS] [element-type: ELEMENT-TYPE] [offset: OFFSET] [usage: USAGE] [draw-arrays?: DRAW-ARRAYS?] [position: POSITION] [radius: RADIUS] [data: DATA] [delete: DELETE] . UNIFORM-ARGS)</procedure>
235
236This extension of the Hyperscene function of the same name (along with Hypergiant’s extension of {{define-pipline}}) is where the majority of the magic of Hypergiant happens. Unlike its cousin, Hypergiant’s {{add-node}}’s {{PIPELINE}} argument accepts the special ''render-pipeline'' object defined by Hypergiant’s {{define-pipeline}} rather than a Hyperscene pipeline.  Because of this, Hyperscene pipelines never need to be manually created. When a non-render-pipeline (i.e. a Hyperscene pipeline) is passed to {{add-node}}, it acts identically to the Hyperscene version, except with the addition of the {{POSITION}} and {{RADIUS}} keywords, and {{DATA}} and {{DELETE}} are keyword arguments.
237
238{{POSITION}} expects a gl-math point. When {{POSITION}} is provided, {{set-node-position!}} is called with {{POSITION}} after the node is created. {{RADIUS}} expects a float. When {{RADIUS}} is provided, {{set-node-bounding-sphere!}} is called with {{RADIUS}} after the node is created.
239
240When {{PIPELINE}} is a render-pipeline the node data that is created is a [[http://wiki.call-cc.org/eggref/4/glls#renderables|glls renderable]] object. {{MESH}}, {{VAO}}, {{MODE}}, {{N-ELEMENTS}}, {{ELEMENT-TYPE}}, and {{OFFSET}} all function as they do when making a renderable. Additionally, {{MESH}} may be passed to {{add-node}} when its VAO has not yet been created (i.e. with [[http://api.call-cc.org/doc/gl-utils/mesh-make-vao%21|{{mesh-make-vao!}}]]), and {{mesh-make-vao!}} will be called automatically, influenced by the optional {{USAGE}} keyword (defaulting to {{#:static}}). {{DRAW-ARRAYS?}} is a boolean that indicates whether or not the renderable’s array rendering function should be used (i.e. {{draw-arrays}} is used instead of {{draw-elements}}). {{DRAW-ARRAYS?}} defaults to {{#t}} if {{MESH}} has no index data, and {{#f}} otherwise. {{add-node}} accepts other keyword {{UNIFORM-ARGS}}, which are used to set the value for each uniform in the pipeline, as required by glls renderable makers.
241
242{{add-node}} appends a number of Hyperscene values to its renderable creation call, for convenience. The following keys and values are added, which must correspond to the names of uniforms in the renderable’s pipeline if they are to be used:
243
244* {{mvp: (current-camera-model-view-projection)}}
245* {{view: (current-camera-view)}}
246* {{projection: (current-camera-projection)}}
247* {{view-projection: (current-camera-view-projection)}}
248* {{camera-position: (current-camera-position)}}
249* {{inverse-transpose-model: (current-inverse-transpose-model)}}
250* {{n-lights: (n-current-lights)}}
251* {{light-positions: (current-light-positions)}}
252* {{light-colors: (current-light-colors)}}
253* {{light-intensities: (current-light-intensities)}}
254* {{light-directions: (current-light-directions)}}
255* {{ambient: (current-ambient-light)}}
256
257It’s worth noting that when {{add-node}} is called with a mesh, no references to that node are kept. Make sure you keep your meshes live, lest they become garbage.
258
259{{add-node}}, along with {{define-pipeline}} does some magic so that things keep working when the program is evaluated (as opposed to compiled), but the end result is that it should Just Work.
260
261
262==== Render-pipelines
263<macro> (define-pipeline PIPELINE-NAME . SHADERS)</macro>
264<macro> (define-alpha-pipeline PIPELINE-NAME . SHADERS)</macro>
265
266Accepts arguments identical to glls’ [[http://api.call-cc.org/doc/glls/define-pipeline|{{define-pipeline}}]], but additionally defines a ''render-pipeline'' object with the name {{PIPELINE-NAME-render-pipeline}}. This render-pipeline object should be passed to {{add-node}}, and contains all the functions necessary to render the pipeline’s renderables. In other words, this creates managed Hyperscene pipeline objects that you don’t need to worry about. Additional work occurs if you evaluate (i.e. don’t compile) a program that uses {{define-pipeline}}.
267
268The functions in the Hyperscene pipelines created by {{define-pipeline}} correspond to the begin render, render, and end render [[http://wiki.call-cc.org/eggref/4/glls#fast-render-functions|“fast” functions]] created by glls. Setting the {{unique-textures?}} parameter, to {{#f}} (for syntax), if a pipeline is known to use only one texture (for each sampler type), may improve speed.
269
270{{define-alpha-pipeline}} works the same, but the creates a pipeline that is potentially transparent to some degree. This additional macro is necessary since Hyperscene renders alpha objects at a different stage, in a different order from opaque objects.
271
272<macro> (export-pipeline . PIPELINES)</macro>
273
274Since {{define-pipeline}} defines multiple objects, this macro exports everything related to each pipeline in {{PIPELINES}}, except for the {{set-SHADER-NAME-renderable-UNIFORM!}} setters. These must be exported individually.
275
276
277==== Pre-defined pipelines and shaders
278For convenience, Hypergiant provides a number of pipelines and shaders to cover common operations. Don’t forget the each pipeline has a {{NAME-render-pipeline}} counterpart that should be used with {{add-node}}.
279
280All of these pipelines use uniforms that are automatically added by {{add-node}} (notably {{mvp}} for the model-view-projection matrix). All of these pipelines uses the same attribute naming scheme used by Hypergiant’s [[#geometry|geometry]] generating functions: {{position}} for the position vector, {{color}} for a three element colour, {{normal}} for the normals, and {{tex-coord}} for texture coordinates. The uniform {{tex}} is used when a sampler is required.
281
282<constant> Pipeline: mesh-pipeline</constant>
283
284'''Attributes'''
285
286* {{position}} – {{#:vec3}}
287
288'''Uniforms'''
289
290* {{mvp}} – {{#:mat4}}
291* {{color}} – {{#:vec3}}
292
293A very basic pipeline for shading with a flat colour.
294
295<constant> Pipeline: color-pipeline</constant>
296
297'''Attributes'''
298
299* {{position}} – {{#:vec3}}
300* {{color}} – {{#:vec3}}
301
302'''Uniforms'''
303
304* {{mvp}} – {{#:mat4}}
305
306A pipeline with a colour associated with each vertex.
307
308<constant> Pipeline: texture-pipeline</constant>
309
310'''Attributes'''
311
312* {{position}} – {{#:vec3}}
313* {{tex-coord}} – {{#:vec2}}
314
315'''Uniforms'''
316
317* {{mvp}} – {{#:mat4}}
318* {{tex}} – {{#:sampler-2d}}
319
320A pipeline with a 2D texture coordinate associated with each vertex.
321
322<constant> Pipeline: sprite-pipeline</constant>
323
324'''Attributes'''
325
326* {{position}} – {{#:vec3}}
327* {{tex-coord}} – {{#:vec2}}
328
329'''Uniforms'''
330
331* {{mvp}} – {{#:mat4}}
332* {{tex}} – {{#:sampler-2d}}
333
334A pipeline with a 2D texture coordinate associated with each vertex, with possible transparency (i.e. defined with {{define-alpha-pipeline}}).
335
336<constant> Pipeline: text-pipeline</constant>
337
338'''Attributes'''
339
340* {{position}} – {{#:vec2}}
341* {{tex-coord}} – {{#:vec2}}
342
343'''Uniforms'''
344
345* {{mvp}} – {{#:mat4}}
346* {{tex}} – {{#:sampler-2d}}
347* {{color}} – {{#:vec3}}
348
349A pipeline for use with a single channel alpha texture, such as a texture atlas. The opaque sections are shaded with the given colour.
350
351<constant> Shader: phong-lighting</constant>
352
353'''Uniforms'''
354
355    ((inverse-transpose-model #:mat4)
356     (camera-position #:vec3)
357     (ambient #:vec3)
358     (n-lights #:int)
359     (light-positions (#:array #:vec3 N-LIGHTS))
360     (light-colors (#:array #:vec3 N-LIGHTS))
361     (light-intensities (#:array #:float N-LIGHTS))
362     (material #:vec4))
363
364Note that all of these uniforms (except {{material}}) are automatically provided by {{add-node}}, although they depend on Hyperscene’s lighting extension to be activated. E.g. {{(activate-extension SCENE (lighting)}}
365
366The function {{make-material}} can be used to create a vector suitable for passing as the {{material}} uniform value.
367
368'''Exports'''
369
370    (light (SURFACE-COLOR #:vec4) (POSITION #:vec3) (NORMAL #:vec3)) -> #:vec4
371
372This shader is designed to provided per-fragment multiple-light Phong lighting, in combination with Hyperscene’s {{lighting}} extension. It provides a single function used for calculating the fragment colour: {{light}}. Given a base, {{SURFACE-COLOR}} the resulting colour after lighting is calculated given the fragments’ {{POSITION}} and {{NORMAL}} (and the uniforms listed above).
373
374When using this shader, make sure it is defined with the proper number of lights, {{N-LIGHTS}}, that will be used by the lighting extension with the shader. This defaults to 8, but can be set with {{set-max-lights!}}.
375
376Here is an example of a simple pipeline using this shader:
377
378<enscript highlight="scheme">    
379(define-pipeline phong-pipeline
380  ((#:vertex input: ((position #:vec3) (normal #:vec3) (tex-coord #:vec2))
381             uniform: ((mvp #:mat4) (model #:mat4))
382             output: ((p #:vec3) (n #:vec3) (t #:vec2)))
383   (define (main) #:void
384     (set! gl:position (* mvp (vec4 position 1.0)))
385     (set! p (vec3 (* model (vec4 position 1))))
386     (set! t tex-coord)
387     (set! n normal)))
388  ((#:fragment input: ((n #:vec3) (p #:vec3) (t #:vec2))
389               use: (phong-lighting)
390               uniform: ((tex #:sampler-2d)
391                         (camera-position #:vec3)
392                         (inverse-transpose-model #:mat4)
393                         (ambient #:vec3)
394                         (n-lights #:int)
395                         (light-positions (#:array #:vec3 8))
396                         (light-colors (#:array #:vec3 8))
397                         (light-intensities (#:array #:float 8))
398                         (material #:vec4))
399               output: ((frag-color #:vec4)))
400   (define (main) #:void
401     (set! frag-color (light (texture tex t) p n)))))
402
403[procedure] (set-max-lights! N)
404</enscript>
405
406This function replaces {{set-max-lights!}}, from Hyperscene. It should be used in the same way. The only difference is that this function selects an appropriate {{phong-lighting}} shader based on the number of lights set. The {{phong-lighting}} shaders differ in the array size of the uniforms, and an appropriate {{N}} value should be used in the uniforms of any pipeline using {{phong-lighting}}: the size of each uniform array should be greater than or equal to {{N}} and a power of 2 from 8 to 64.
407
408<constant> Shader: calc-bone-matrix</constant>
409
410'''Uniforms'''
411
412    ((bone-matrices (#:array #:mat4 100)))
413
414Note that this uniform is automatically provided when creating an animated model with {{add-new-animated-model}}.
415
416'''Exports'''
417
418    (calc-bone-matrix (BONE-INDICES #:vec4) (BONE-WEIGHTS #:vec3)) -> #:mat4
419
420This shader function calculates the matrix resulting from taking the given {{BONE-INDICES}} and {{BONE-WEIGHTS}} and summing the weighted matrices taken from the uniform {{bone-matrices}} array.
421
422Here’s a simple shader using this shader:
423
424<enscript highlight="scheme">    
425(define-pipeline bone-pipeline
426  ((#:vertex input: ((position #:vec3) (tex-coord #:vec2)
427                     (blend-indexes #:vec4) (blend-weights #:vec4))
428             uniform: ((mvp #:mat4)
429                       (bone-matrices (#:array #:mat4 100)))
430             use: (calc-bone-matrix)
431             output: ((tex-c #:vec2)))
432   (define (main) #:void
433     (set! gl:position (* mvp
434                          (calc-bone-matrix blend-indexes
435                                            blend-weights)
436                          (vec4 position 1.0)))
437     (set! tex-c tex-coord)))
438  ((#:fragment input: ((tex-c #:vec2))
439               uniform: ((tex #:sampler-2d))
440           output: ((frag-color #:vec4)))
441   (define (main) #:void
442     (set! frag-color (texture tex tex-c)))))
443</enscript>
444
445
446==== Geometry
447Hypergiant provides numerous functions for generating [[http://api.call-cc.org/doc/gl-utils#sec:gl-utils-mesh|gl-utils mesh]] primitives. The attributes of these meshes are all named with the same convention as the [[#pre-defined-pipelines-and-shaders|pre-defined pipelines]]: The vertex position, normal, three element colour, and texture coordinate attributes are named {{position}}, {{normal}}, {{color}}, and {{tex-coord}}, respectively. Positions and normals are always {{vec3}}s, represented as floats in memory, while the type of the other attributes can be controlled with arguments.
448
449<procedure> (line-mesh POINTS [mode: MODE])</procedure>
450
451Create a non-indexed mesh of {{POINTS}}. {{MODE}} should be a valid argument to {{mode->gl}},  defaulting to {{#:line-strip}}.
452
453<procedure> (rectangle-mesh WIDTH HEIGHT [centered?: CENTERED?] [texture-width: TEXTURE-WIDTH] [texture-height: TEXTURE-HEIGHT] [texture-offset: TEXTURE-OFFSET] [texture: TEXTURE] [color: COLOR] [winding: WINDING] [mode: MODE] [texture-type: TEXTURE-TYPE] [color-type: COLOR-TYPE] [index-type: INDEX-TYPE])</procedure>
454
455Create a rectangular mesh of {{WIDTH}} and {{HEIGHT}}. If {{CENTERED?}} is not {{#f}}, the centre of the rectangle with be at the origin, otherwise the bottom left corner will be (default is {{#t}}). When both {{TEXTURE-WIDTH}} and {{TEXTURE-HEIGHT}} are specified, two element texture coordinates are added to the mesh, with {{TEXTURE-OFFSET}} representing the upper left corner, defaulting to {{(0 0)}}. Alternately, {{TEXTURE}} may be supplied, which expects a function of one argument: the index of a vertex. This texture function should return a two element list of the texture coordinate at that index. The rectangle mesh vertices are ordered as follows: {{(upper-left upper-right lower-left lower-right)}}. Likewise, {{COLOR}} expects a similar function that accepts one index as an argument, but should return a three element list of colour values. {{WINDING}} controls the direction of the vertex winding, either counter-clockwise ({{#:ccw}}, the default), or clockwise ({{#:cw}}). {{MODE}} should be a valid argument to {{mode->gl}},  defaulting to {{#:triangles}}. {{TEXTURE-TYPE}}, {{COLOUR-TYPE}}, and {{INDEX-TYPE}} control the in-memory type of the texture attribute, the color attribute, and the index, and should be a valid argument to {{type->gl}}. These all default to {{#:ushort}}.
456
457<procedure> (circle-mesh RADIUS RESOLUTION [texture-radius: TEXTURE-RADIUS] [texture-offset: TEXTURE-OFFSET] [texture: TEXTURE] [color: COLOR] [winding: WINDING] [mode: MODE] [texture-type: TEXTURE-TYPE] [color-type: COLOR-TYPE] [index-type: INDEX-TYPE])</procedure>
458
459Create a circular mesh with {{RADIUS}} and {{RESOLUTION}} triangular slices, with the centre of the circle at the origin. When {{TEXTURE-RADIUS}} is specified, two element texture coordinates are added to the mesh, with {{TEXTURE-OFFSET}} representing the centre of the circle, defaulting to {{(0.5 0.5)}}. Alternately, {{TEXTURE}} may be supplied, which expects a function of one argument: the index of a vertex. This texture function should return a two element list of the texture coordinate at that index. The circle mesh vertices are ordered with the first vertex at {{(0 0)}}, then moving in a circle starting at {{(RADIUS 0)}} and proceeding counter-clockwise for a total of {{RESOLUTION + 1}} vertices. Likewise, {{COLOR}} expects a similar function that accepts one index as an argument, but should return a three element list of colour values. {{WINDING}} controls the direction of the vertex winding, either counter-clockwise ({{#:ccw}}, the default), or clockwise ({{#:cw}}). {{MODE}} should be a valid argument to {{mode->gl}},  defaulting to {{#:triangles}}. {{TEXTURE-TYPE}}, {{COLOUR-TYPE}}, and {{INDEX-TYPE}} control the in-memory type of the texture attribute, the color attribute, and the index, and should be a valid argument to {{type->gl}}. These all default to {{#:ushort}}.
460
461<procedure> (cube-mesh LENGTH [normals?: NORMALS?] [cube-map?: CUBE-MAP?] [texture: TEXTURE] [color: COLOR] [winding: WINDING] [mode: MODE] [texture-type: TEXTURE-TYPE] [color-type: COLOR-TYPE] [index-type: INDEX-TYPE])</procedure>
462
463Create a cube mesh with sides of {{LENGTH}} with the centre of the cube at the origin. Each face of the cube has a unique set of vertices – i.e. no face shares vertices. When {{NORMALS?}} is {{#t}}, normals are added to the mesh. When {{CUBE-MAP?}} is {{#t}}, three element texture coordinates are added to the mesh, corresponding to a unit-cube. Alternately, {{TEXTURE}} may be supplied, which expects a function of one argument: the index of a vertex. This texture function should return a three element list of the texture coordinate at that index. The cube mesh vertices are ordered as follows: each face has vertices {{(upper-left upper-right lower-left lower-right)}}, and the faces are ordered {{(front right back left top bottom)}}. The up direction for each face can be seen in the image below:
464
465[[image:https://github.com/AlexCharlton/hypergiant/raw/master/doc-images/cube-mapping.png|Cube wrapping]]
466
467Likewise, {{COLOR}} expects a similar function that accepts one index as an argument, but should return a three element list of colour values. {{WINDING}} controls the direction of the vertex winding, either counter-clockwise ({{#:ccw}}, the default), or clockwise ({{#:cw}}). {{MODE}} should be a valid argument to {{mode->gl}},  defaulting to {{#:triangles}}. {{TEXTURE-TYPE}}, {{COLOUR-TYPE}}, and {{INDEX-TYPE}} control the in-memory type of the texture attribute, the color attribute, and the index, and should be a valid argument to {{type->gl}}. {{TEXTURE-TYPE}} defaults to {{#:float}}, while {{COLOUR-TYPE}} and {{INDEX-TYPE}} default to {{#:ushort}}.
468
469<procedure> (sphere-mesh RADIUS RESOLUTION [type: TYPE] [normals? NORMALS?] [texture-width: TEXTURE-WIDTH] [texture-height: TEXTURE-HEIGHT] [texture-offset: TEXTURE-OFFSET] [cube-map? CUBE-MAP?] [texture: TEXTURE] [color: COLOR] [winding: WINDING] [mode: MODE] [texture-type: TEXTURE-TYPE] [color-type: COLOR-TYPE] [index-type: INDEX-TYPE])</procedure>
470
471Create a spherical mesh of {{RADIUS}} with the centre of the sphere at the origin. Depending on {{TYPE}}, the way the sphere is created will differ: {{#:uv}} will create a UV sphere – with vertices positioned on longitude/latitude points – {{#:cube}} will create a cube sphere – with vertices positioned on a deformed cube. The former is useful for 2D texture mapping, but will necessarily have increasingly large deformation towards the poles, and lower resolution near the equator. The latter is useful for a cube-mapped texture, for minimal deformation. The images below illustrates a UV sphere and cube sphere, respectively.
472
473[[image:https://github.com/AlexCharlton/hypergiant/raw/master/doc-images/uv-sphere.gif|UV sphere]] [[image:https://github.com/AlexCharlton/hypergiant/raw/master/doc-images/cube-sphere.gif|Cube sphere]]
474
475For the UV sphere, {{RESOLUTION}} sets the number of longitudinal subdivisions, half of which is the number of latitudinal subdivisions ({{RESOLUTION}} must be a factor of 2). Setting both {{TEXTURE-WIDTH}} and {{TEXTURE-HEIGHT}} for a UV sphere causes 2 element texture coordinates to be added to the mesh, with {{TEXTURE-OFFSET}} representing the upper left corner of the texture, defaulting to {{(0 0)}}. The texture’s upper left corner is mapped to the left side of the sphere, wrapping counter-clockwise such that the left half of the texture corresponds to the front half of the sphere. Alternately, {{TEXTURE}} may be supplied, which expects a function of one argument: the index of a vertex. This texture function should return a two element list of the texture coordinate at that index. The cube mesh vertices are ordered as a rectangular array with {{RESOLUTION + 1}} columns and {{RESOLUTION/2 + 1}} rows. The first row corresponds to the “north” pole, while the last corresponds to the “south” pole. The first column has the same position as the last. This array is wrapped counter-clockwise around the sphere, starting on the left. Likewise, {{COLOR}} expects a similar function that accepts one index as an argument, but should return a three element list of colour values.
476
477For the cube sphere, {{RESOLUTION}} sets the number of vertical and horizontal subdivision of each face of the cube. Like the cube mesh, each face of the cube has a unique set of vertices – i.e. no face shares vertices. When {{CUBE-MAP?}} is {{#t}}, three element texture coordinates are added to the mesh, corresponding to a unit-sphere. Alternately, {{TEXTURE}} may be supplied, which expects a function of one argument: the index of a vertex. This texture function should return a three element list of the texture coordinate at that index. The cube mesh vertices are ordered as follows: each face is a rectangular array of {{RESOLUTION + 1}} by {{RESOLUTION + 1}} points, and the faces are ordered {{(front right back left top bottom)}}, the same as the {{cube-mesh}} faces. Likewise, {{COLOR}} expects a similar function that accepts one index as an argument, but should return a three element list of colour values.
478
479For both types of spheres, when {{NORMALS?}} is {{#t}}, normals are added to the mesh. {{WINDING}} controls the direction of the vertex winding, either counter-clockwise ({{#:ccw}}, the default), or clockwise ({{#:cw}}). {{MODE}} should be a valid argument to {{mode->gl}},  defaulting to {{#:triangles}}. {{TEXTURE-TYPE}}, {{COLOUR-TYPE}}, and {{INDEX-TYPE}} control the in-memory type of the texture attribute, the color attribute, and the index, and should be a valid argument to {{type->gl}}. {{TEXTURE-TYPE}} defaults to {{#:float}} for cube spheres and {{#:ushort}} for UV spheres, while {{COLOUR-TYPE}} and {{INDEX-TYPE}} default to {{#:ushort}}.
480
481<procedure> (cylinder-mesh LENGTH RADIUS VERTICAL-SUBDIVISIONS RESOLUTION [normals? NORMALS?] [texture-width: TEXTURE-WIDTH] [texture-height: TEXTURE-HEIGHT] [texture-offset: TEXTURE-OFFSET] [texture: TEXTURE] [color: COLOR] [winding: WINDING] [mode: MODE] [texture-type: TEXTURE-TYPE] [color-type: COLOR-TYPE] [index-type: INDEX-TYPE])</procedure>
482
483Create a cylindrical mesh of {{LENGTH}} and {{RADIUS}}, with the length oriented along the Y-axis, and the centre of the bottom of the cylinder at the origin. {{VERTICAL-SUBDIVISIONS}} sets the number of subdivisions along the length of the mesh, while {{RESOLUTION}} sets the number of subdivisions along the circumference. Setting both {{TEXTURE-WIDTH}} and {{TEXTURE-HEIGHT}} causes 2 element texture coordinates to be added to the mesh, with {{TEXTURE-OFFSET}} representing the upper left corner of the texture, defaulting to {{(0 0)}}. The texture’s upper left corner is mapped to the left side of the cylinder, wrapping counter-clockwise such that the left half of the texture corresponds to the front half of the cylinder. Alternately, {{TEXTURE}} may be supplied, which expects a function of one argument: the index of a vertex. This texture function should return a two element list of the texture coordinate at that index. The cube mesh vertices are ordered as a rectangular array with {{RESOLUTION + 1}} columns and {{VERTICAL-SUBDIVISIONS + 1}} rows. The first row corresponds to the top of the cylinder pole, while the last corresponds to the bottom. The first column has the same position as the last. This array is wrapped counter-clockwise around the sphere, starting on the left. Likewise, {{COLOR}} expects a similar function that accepts one index as an argument, but should return a three element list of colour values. When {{NORMALS?}} is {{#t}}, normals are added to the mesh. {{WINDING}} controls the direction of the vertex winding, either counter-clockwise ({{#:ccw}}, the default), or clockwise ({{#:cw}}). {{MODE}} should be a valid argument to {{mode->gl}},  defaulting to {{#:triangles}}. {{TEXTURE-TYPE}}, {{COLOUR-TYPE}}, and {{INDEX-TYPE}} control the in-memory type of the texture attribute, the color attribute, and the index, and should be a valid argument to {{type->gl}}. {{TEXTURE-TYPE}}, {{COLOUR-TYPE}} and {{INDEX-TYPE}} all default to {{#:ushort}}.
484
485
486==== Animated sprites
487Hypergiant provides functions that handle the common needs for animated sprites. Such sprites use a sprite sheet – a texture that contains all of the frames of the animation, arranged in a grid. From this texture a {{sprite-sheet}} object is created, which is a mesh of rectangles and texture coordinates corresponding to the frames on the texture. Based on these sprite sheets, {{animations}} are created, which are essentially a list of frames, in the order that they should be played. A animation may be used with more than one sprite sheet (although, if the frames of each sprite sheet doesn’t correspond to each other, things will probably be weird).
488
489<procedure> (make-sprite-sheet TEX-WIDTH TEX-HEIGHT FRAME-WIDTH FRAME-HEIGHT [rows: ROWS] [columns: COLUMNS] [x-offset: X-OFFSET] [y-offset: Y-OFFSET] [centered?: CENTERED?] [texture-type: TEXTURE-TYPE])</procedure>
490
491Return a mesh, similar to a rectangular mesh, but with multiple rectangles with different texture coordinates. The rectangles will be sized {{FRAME-WIDTH}} by {{FRAME-HEIGHT}}. If {{CENTERED?}} is not {{#f}}, the centre of the rectangles with be at the origin, otherwise the bottom left corner will be (default is {{#t}}). The texture coordinates will be taken as though the rectangles were arranged in a grid over a texture of dimensions {{TEX-WIDTH}} by {{TEX-HEIGHT}}, with the number of rows and columns that can fit on these dimensions, unless {{ROWS}} or {{COLUMNS}} is specified. Offsets to the top left corner of the tiled area of the texture can be provided with {{X-OFFSET}} and {{Y-OFFSET}}. {{TEXTURE-TYPE}} controls the in-memory type of the texture attribute, and should be a valid argument to {{type->gl}}, defaulting to {{#:ushort}}.
492
493The meshes returned by {{make-sprite-sheet}} are intended as an argument to {{make-animated-sprite}} or {{add-new-animated-sprite}}. A single sprite sheet cannot be used with animated sprites with different textures. Consider using {{mesh-copy}} if you need an identical sprite sheet.
494
495<procedure> (make-animation TYPE FRAMES FRAME-RATE)</procedure>
496
497An animation is an opaque type that describes an animation sequence, as given in a sprite sheet. The {{TYPE}} may be one of {{#:once}} or {{#:loop}}, which respectively define animations that are only ever played once, or that loop. {{FRAMES}} is a list of integers, that define subsequent frames in the given animation, as ordered in the sprite sheet (or sheets) that is to be associated with the animation (index on the sprite sheet from left to right, top to bottom). {{FRAME-RATE}} is the desired speed that the animation should be played at, given in seconds between frames.
498
499For a convenient way of defining multiple animations, see {{make-animation-alist}}.
500
501<procedure> (animation? X)</procedure>
502
503Return {{#t}} if {{X}} is an animation object.
504
505<procedure> (make-animation-alist ANIMATIONS [frame-rate: FRAME-RATE])</procedure>
506
507Takes an alist, {{ANIMATIONS}} of {{(KEY . (TYPE FRAMES [ANIMATION-FRAME-RATE])}}, where {{TYPE}} and {{FRAMES}} are as required for {{make-animation}}. {{ANIMATION-FRAME-RATE}} is an optional argument so long as the keyword argument {{FRAME-RATE}} is supplied. Returns an alist of {{(KEY . ANIMATION)}} pairs.
508
509<procedure> (make-animated-sprite NODE BASE-ANIMATION)</procedure>
510
511Create a new animated sprite, using the previously created {{NODE}}. {{BASE-ANIMATION}} is a (looping) animation that the sprite should use upon initialization. {{NODE}} should have been created with a sprite-sheet mesh, and with a corresponding texture. If the pipeline {{sprite-pipeline}} will be used for the animated sprite, consider using {{add-new-animated-sprite}}, which performs the node creation as well.
512
513<procedure> (animated-sprite? X)</procedure>
514
515Return {{#t}} if {{X}} is an animated sprite object.
516
517<procedure> (add-new-animated-sprite PARENT SPRITE-SHEET TEXTURE BASE-ANIMATION)</procedure>
518
519Returns a new animated sprite object that has been added to the Hyperscene node {{PARENT}}. The node for this sprite is created with {{sprite-pipeline}}. {{SPRITE-SHEET}} is a sprite sheet mesh that has been created with {{make-sprite-sheet}}. {{TEXTURE}} is the GL texture ID associated with the sprite sheet. {{BASE-ANIMATION}} is a (looping) animation that the sprite should use upon initialization.
520
521<procedure> (animated-sprite-node ANIMATED-SPRITE)</procedure>
522
523Return the node associated with {{ANIMATED-SPRITE}}.
524
525<procedure> (set-animation! ANIMATED-SPRITE ANIMATION)</procedure>
526
527Set the {{ANIMATION}} that the {{ANIMATED-SPRITE}} should be playing. {{#:once}} type animations are played once before the last looping animation resumes, while {{#:loop}} type animations will loop continuously until another {{#:loop}} animation is set. Setting an animation that is already the current animation of the {{ANIMATED-SPRITE}} has no effect.
528
529<procedure> (current-animation ANIMATED-SPRITE)</procedure>
530
531Return the animation that the {{ANIMATED-SPRITE}} is currently playing.
532
533<procedure> (update-animated-sprite! ANIMATED-SPRITE DELTA)</procedure>
534
535Update the {{ANIMATED-SPRITE}} given the time interval {{DELTA}}, changing the current frame of the sprite if enough time has elapsed since the last frame. This should be called every frame that the {{ANIMATED-SPRITE}} is to be animated.
536
537
538==== Inter-Quake Models
539[[http://sauerbraten.org/iqm/|Inter-Quake Models]] are an open standard for rigged models, with support across a range of tools. Hypergiant supports their loading, and creating meshes and animated models with the resulting IQM objects.
540
541<procedure> (load-iqm IQM-FILE [BASE-IQM])</procedure>
542
543Load an IQM record from the given {{IQM-FILE}}. For IQM files that only provide an animation, a {{BASE-IQM}} is necessary in order to generate a Hypergiant animation object. When {{load-iqm}} is called with a {{BASE-IQM}}, any animations created are added to the {{BASE-IQM}}.
544
545<record> (iqm meshes vertex-arrays n-vertexes n-triangles triangles adjacencies joints animations flags comment)</record>
546
547The record created by {{load-iqm}}.
548
549<parameter> iqm-global-flags</parameter>
550
551An alist of flags that are recognized by {{load-iqm}}. Defaults to {{()}}.
552
553<parameter> vertex-array-flags</parameter>
554
555An alist of vertex-array flags that are recognized by {{load-iqm}}. Defaults to {{()}}.
556
557<parameter> animation-flags</parameter>
558
559An alist of animation flags that are recognized by {{load-iqm}}. Defaults to {{((#:loop . 1))}}.
560
561<procedure> (iqm->mesh IQM ATTRIBUTES)</procedure>
562
563Create a mesh from the given IQM object, with the provided list of ATTRIBUTES. This creates a mesh using all of the vertices of the IQM.
564
565<procedure> (iqm->meshes IQM ATTRIBUTES)</procedure>
566
567Create a list of mesh for each mesh defined in the given IQM object, with the provided list of ATTRIBUTES.
568
569<parameter> normalized-attributes</parameter>
570
571A list of attribute symbols which should be normalized when creating a mesh from an IQM (with {{iqm->mesh(s)}}). Defaults to {{(blend-weights color)}}.
572
573
574==== Animated models
575Animated models are an opaque object similar to animated sprites, but for rigged models. Animated models are used with the same animation getting and setting functions as [[http://wiki.call-cc.org/eggref/4/hypergiant#animated-sprites|animated sprites]], i.e. {{current-animation}} and {{set-animation!}}. Animations suitable for animated models are created when loading IQM files containing animations (which can be referenced with {{iqm-animations}}).
576
577<procedure> (add-new-animated-model PARENT PIPELINE mesh: MESH base-animation: BASE-ANIMATION . ARGS)</procedure>
578
579Extends {{add-node}}, returning an animated model object. This function requires the following keyword arguments: {{MESH}}, a mesh corresponding to the IQM (made with e.g. {{iqm->mesh}}), {{BASE-ANIMATION}} the initial animation to use for the animated model.
580
581<procedure> (update-animated-model! ANIMATED-MODEL DELTA)</procedure>
582
583Update the {{ANIMATED-MODEL}} given the time interval {{DELTA}}, changing the current frame of the model if enough time has elapsed since the last frame, tweening between frames. This should be called every frame that the {{ANIMATED-MODEL}} is to be animated.
584
585
586==== Particle system
587Hypergiant’s particle system is implemented as an extension to Hyperscene. It introduces two concepts: ''emitters'' and ''particles''. Emitters are a record that is created when added to a scene (via {{add-emitter}}), similar to a node. These records contain a reference to the node that is used to move them around the scene. Emitters also share properties with [[http://wiki.call-cc.org/eggref/4/gl-utils#gl-utils-mesh|meshes]]. A component of the emitter is essentially a mesh where each vertex corresponds to a particle, and the same attribute system is shared with meshes.
588
589Emitters are used to “emit” a number of particles. These particles are created and updated via the {{for-emitter}} macro.
590
591<procedure> (particles)</procedure>
592
593Returns a pointer to the Hyperscene extension of the particle system. The extension must be activated for any scenes that will use the particle system. I.e. {{(activate-extension SCENE (particles))}}
594
595<record> emitter</record>
596
597The emitter record returned by {{add-emitter}}.
598
599<procedure> (emitter? X)</procedure>
600
601Return {{#t}} if {{X}} is a emitter record.
602
603<procedure> (emitter-node EMITTER)</procedure>
604
605Return the node of {{EMITTER}} that can be used to position the emitter in its scene. Do not use {{delete-node}} on this node: use {{delete-emitter}} on the emitter instead.
606
607<procedure> (emitter-n-particles EMITTER)</procedure>
608
609Return the current number of particles created by {{EMITTER}}.
610
611<procedure> (emitter-max-particles EMITTER)</procedure>
612
613Return the maximum number of particles that can be created by {{EMITTER}}.
614
615<procedure> (add-emitter PARENT PIPELINE [attributes: ATTRIBUTES] [n-particles: N-PARTICLES]  [position: POSITION] [radius: RADIUS] . UNIFORM-ARGS)</procedure>
616
617Add a new emitter to the node or scene {{PARENT}}, returning an emitter record. {{PIPELINE}} is the render-pipeline used to render the emitter.
618
619{{ATTRIBUTES}} is a list of the kind that would be passed as the {{ATTRIBUTES}} argument in [[http://api.call-cc.org/doc/gl-utils/make-mesh|make-mesh]], a list in the form:
620
621    (NAME TYPE N [normalized: NORMALIZED])
622
623where {{NAME}} is the attribute name (as a symbol), {{TYPE}} is the type of the attribute as accepted by {{type->gl}}, {{N}} is the number of elements in the attribute, {{NORMALIZED}} is a boolean value indicating whether the attribute’s values should be normalized (defaulting to {{#f}}).
624
625These attributes correspond to the properties of each particle. All emitters are given the attribute {{(position #:float 3)}}, so {{ATTRIBUTES}} is used to define any attributes beyond this default one.
626
627{{N-PARTICLES}} is a required argument, which defines the maximum number of particles that the emitter may create. {{POSITION}} is used to define the initial position of the emitter, while {{RADIUS}} is used to define the radius of its bounding sphere. Unlike most nodes, the radius of the bounding sphere of an emitter cannot be meaningfully changed after it is created, so make sure to properly initialize it. As with {{add-node}}, {{UNIFORM-ARGS}} is the set of other keywords used to set the value for each uniform in the pipeline, as required by the [[http://wiki.call-cc.org/eggref/4/glls#renderables|glls renderable]] makers, specific to the {{PIPELINE}} that is used.
628
629<procedure> (delete-emitter EMITTER)</procedure>
630
631Delete the {{EMITTER}}, removing it from its scene.
632
633<macro> (for-emitter (PARTICLE-VAR EMITTER ATTRIBUTES) BEGIN UPDATE)</macro>
634
635Iterates through the particles in {{EMITTER}}, assigning each one in sequence to the variable {{PARTICLE-VAR}} and executing {{UPDATE}}. The {{BEGIN}} form is used to perform any one-time actions that require the same scope, e.g. adding new particles. Particles added in {{BEGIN}} are not processed with {{UPDATE}}.
636
637{{ATTRIBUTES}} is a list of the emitter’s attributes that should have accessors bound. Each attribute has a {{(ATTRIBUTE-ref PARTICLE)}} and {{(ATTRIBUTE-set! PARTICLE VALUE)}} function bound in the scope to the {{BEGIN}} and {{UPDATE}} forms, which are used to reference and set the attributes of the given particle. {{ATTRIBUTE-ref}} returns an srfi-4 vector of the type and number of the associated attribute, while {{ATTRIBUTE-set!}}’s {{VALUE}} should be an srfi-4 vector of the type and number of the attribute.
638
639<procedure> (add-particle EMITTER)</procedure>
640
641Return a pointer representing a new particle from {{EMITTER}}. This particle is not initialized in any way, and should be done so using the accessors that are bound in {{for-emitter}}.
642
643<procedure> (delete-particle EMITTER PARTICLE)</procedure>
644
645Delete the given {{PARTICLE}} from {{EMITTER}}.
646
647
648==== Text
649Hypergiant reexports all of [[http://wiki.call-cc.org/eggref/4/gl-type|gl-type]] with no modifications. The following utilities are additionally provided:
650
651<procedure> (update-string-mesh! MESH NODE STRING FACE)</procedure>
652
653Used to modify an existing string mesh, this is similar to calling [[http://api.call-cc.org/doc/gl-type/string-mesh|{{string-mesh}}]] with the {{mesh:}} argument, but additionally updates the {{NODE}}’s renderable to properly display the new {{STRING}}. {{MESH}} should be a mesh that was created with {{string-mesh}}. When the mesh’s VAO is created, it must have a non-static usage (i.e. setting {{add-node}}’s {{usage:}} keyword to {{#:dynamic}} or {{#:stream}}). {{NODE}} is a node associated with that mesh, which must have been created with a render-pipeline. {{FACE}} is a font face created with [[http://api.call-cc.org/doc/gl-type/load-face|{{load-face}}]]. The number of graphical characters (non-whitespace characters in the char-set of {{FACE}}) in {{STRING}} must be equal to or less than the number of graphical characters in the string used to create {{MESH}}.
654
655
656==== Colors
657Some color functions are provided for convenience. These are nothing more than f32vectors, which are useful as uniform values.
658
659<procedure> (make-rgb-color R G B [NON-GC?])</procedure>
660<procedure> (make-rgba-color R G B A [NON-GC?])</procedure>
661
662Create a three or four element f32vector with values {{(R G B [A])}}. If {{NON-GC?}} is set to {{#t}}, the color will be located in a non-garbage collected region of memory (so it will not be moved, although it will still be collected when non-accessible).
663
664<procedure> (color-r COLOR)</procedure>
665<procedure> (color-g COLOR)</procedure>
666<procedure> (color-b COLOR)</procedure>
667<procedure> (color-a COLOR)</procedure>
668<procedure> (set-color-r! COLOR)</procedure>
669<procedure> (set-color-g! COLOR)</procedure>
670<procedure> (set-color-b! COLOR)</procedure>
671<procedure> (set-color-a! COLOR)</procedure>
672
673Getters and setters for colors. {{color-a}} and {{set-color-a!}} can only be used with 4 element (alpha) colors.
674
675<constant> black</constant>
676<constant> white</constant>
677
678Two pre-defined RGB colors, with unambiguous names.
679
680
681==== Math
682Hypergiant reexports all of [[http://wiki.call-cc.org/eggref/4/gl-math|gl-math]] with no modifications. The following math functions are additionally provided:
683
684<procedure> (random-normal [MEAN] [VARIANCE])</procedure>
685
686Return a semi-random floating point value. The values will be generated to fall in a a normal distribution around {{MEAN}}, defaulting to 0, with the given {{VARIANCE}}, defaulting to 1.
687
688<procedure> (random-float)</procedure>
689
690Return a random floating point value between -1 and 1.
691
692<procedure> (next-power-of-two N)</procedure>
693
694Returns the next power of two for the positive integer {{n}}.
695
696<procedure> (clamp X LOWER UPPER)</procedure>
697
698Given the number {{X}}, return a value that is the same, so long as it is not greater than {{UPPER}} or less than {{LOWER}}: in these cases, return the upper or lower bound, respectively.
699
700
701===== Vector operations
702The following operate on the 3 element vectors ([[http://wiki.call-cc.org/eggref/4/gl-math#vector-operations|{{point}}s]]) defined in gl-math.
703
704<procedure> (vclamp VECTOR LOWER UPPER [NON-GC?])</procedure>
705<procedure> (vclamp! VECTOR LOWER UPPER)</procedure>
706
707Return a point with each element of {{VECTOR}} clamped to {{LOWER}} and {{UPPER}}. {{vclamp!}} destructively modifies the original vector. If {{NON-GC?}} is {{#t}}, the point is created in a non-garbage-collected area (the memory will still be freed when there are no more references to the vector).
708
709<procedure> (v/ VECTOR S [RESULT])</procedure>
710
711Return the result of the dividing each element of {{VECTOR}} with scalar {{S}}. If a vector {{RESULT}} is given, it will be modified to contain the result. If {{RESULT}} is {{#t}} the returned value will be an f32vector located in non-garbage-collected memory (the memory will still be freed when there are no more references to the matrix). If {{RESULT}} is not provided, the returned value will be an f32vector located in normal garbage collected memory.
712
713<procedure> (vround VECTOR [NON-GC?])</procedure>
714<procedure> (vfloor VECTOR [NON-GC?])</procedure>
715<procedure> (vceiling VECTOR [NON-GC?])</procedure>
716<procedure> (vtruncate VECTOR [NON-GC?])</procedure>
717
718Return a point that has had the operation {{round}}, {{floor}}, {{ceiling}}, or {{truncate}} performed on each element of {{VECTOR}}. If {{NON-GC?}} is {{#t}}, the point is created in a non-garbage-collected area (the memory will still be freed when there are no more references to the vector).
719
720
721=== Examples
722See the [[https://github.com/AlexCharlton/Hypergiant/tree/master/examples|examples directory]] for several examples that use Hypergiant.
723
724The following example shows the creation and addition of a multi-coloured square to a scene:
725
726<enscript highlight="scheme">    
727(import chicken scheme)
728(use hypergiant)
729
730(define scene (make-parameter #f))
731(define camera (make-parameter #f))
732
733(define square (rectangle-mesh 1 1 color: (lambda (i)
734                                            (list-ref '((1 0 0)
735                                                        (0 1 0)
736                                                        (0 0 1)
737                                                        (1 0 1))
738                                                      i))))
739
740(define (init)
741  (scene (make-scene))
742  (camera (make-camera #:perspective #:orbit (scene)))
743  (add-node (scene) color-pipeline-render-pipeline
744            mesh: square))
745
746(start 400 400 "Simple" init: init resizable: #f)
747</enscript>
748
749
750=== Resources
751[[http://alex-charlton.com/posts/Prototype_to_polish_Making_games_in_CHICKEN_Scheme_with_Hypergiant/|Prototype to polish: Making games in CHICKEN Scheme with Hypergiant]] is a blog post that details the creation of a simple game with Hypergiant.
752
753
754=== Version history
755
756==== Version 0.4.0
7578 August 2015
758
759Make sure gl-math is up to date before updating Hypergiant.
760
761* Add Inter-Quake Model loading and animation
762* Support for Retina displays
763
764
765==== Version 0.3.0
76623 January 2015
767
768Make sure Hyperscene, soil, glls, and gl-math are up to date before updating Hypergiant.
769
770* Add pre & post-rendering keywords to {{start}}
771* More control over camera viewports and projections (via Hyperscene)
772
773
774==== Version 0.2.0
77518 January 2015
776
777Make sure Hyperscene, soil, glls, gl-utils, noise, and gl-type are up to date before updating Hypergiant.
778
779* Add particle system
780* Add clipboard support
781* Multisampling enabled by default
782* OS X support
783
784
785==== Version 0.1.0
786* Initial release
787
788
789=== Source repository
790Source available on [[https://github.com/AlexCharlton/hypergiant|GitHub]].
791
792Bug reports and patches welcome! Bugs can be reported via GitHub or to alex.n.charlton at gmail.
793
794
795=== Author
796Alex Charlton
797
798
799=== License
800BSD-2-Clause
Note: See TracBrowser for help on using the repository browser.