Full Code of Vladar4/nimgame2 for AI

master afd289aefd84 cached
195 files
2.8 MB
741.7k tokens
12 symbols
1 requests
Download .txt
Showing preview only (2,965K chars total). Download the full file or copy to clipboard to get everything.
Repository: Vladar4/nimgame2
Branch: master
Commit: afd289aefd84
Files: 195
Total size: 2.8 MB

Directory structure:
gitextract_oovdsi4y/

├── LICENSE
├── README.md
├── STYLE.md
├── demos/
│   ├── README.md
│   ├── assets/
│   │   ├── csv/
│   │   │   ├── atlas.csv
│   │   │   ├── map0.csv
│   │   │   └── map_camera_test.csv
│   │   └── mus/
│   │       ├── absolu.mod
│   │       ├── biotech.xm
│   │       ├── cancan.mod
│   │       └── cornered!.xm
│   ├── demo1/
│   │   ├── README.md
│   │   ├── demo1.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo10/
│   │   ├── README.md
│   │   ├── demo10.nim
│   │   ├── earth.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo11/
│   │   ├── README.md
│   │   ├── demo11.nim
│   │   ├── earth.nim
│   │   └── mainscene.nim
│   ├── demo12/
│   │   ├── README.md
│   │   ├── demo12.nim
│   │   └── mainscene.nim
│   ├── demo13/
│   │   ├── README.md
│   │   ├── cursor.nim
│   │   ├── demo13.nim
│   │   └── mainscene.nim
│   ├── demo14/
│   │   ├── README.md
│   │   ├── demo14.nim
│   │   ├── dwarf.nim
│   │   └── mainscene.nim
│   ├── demo15/
│   │   ├── README.md
│   │   ├── demo15.nim
│   │   └── mainscene.nim
│   ├── demo16/
│   │   ├── README.md
│   │   ├── demo16.nim
│   │   └── mainscene.nim
│   ├── demo17/
│   │   ├── README.md
│   │   ├── btnCircle.nim
│   │   ├── btnSquare.nim
│   │   ├── demo17.nim
│   │   └── mainscene.nim
│   ├── demo18/
│   │   ├── README.md
│   │   ├── demo18.nim
│   │   └── mainscene.nim
│   ├── demo19/
│   │   ├── README.md
│   │   ├── demo19.nim
│   │   └── mainscene.nim
│   ├── demo2/
│   │   ├── README.md
│   │   ├── demo2.nim
│   │   ├── earth.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo20/
│   │   ├── README.md
│   │   ├── demo20.nim
│   │   └── mainscene.nim
│   ├── demo21/
│   │   ├── README.md
│   │   ├── demo21.nim
│   │   ├── joypoint.nim
│   │   └── mainscene.nim
│   ├── demo22/
│   │   ├── README.md
│   │   ├── demo22.nim
│   │   ├── mainscene.nim
│   │   └── video.mpg
│   ├── demo23/
│   │   ├── README.md
│   │   ├── demo23.nim
│   │   ├── mainscene.nim
│   │   └── private/
│   │       ├── border_fill_graphic.nim
│   │       ├── circle_graphic.nim
│   │       └── frame.nim
│   ├── demo3/
│   │   ├── README.md
│   │   ├── demo3.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo4/
│   │   ├── README.md
│   │   ├── demo4.nim
│   │   ├── dwarf.nim
│   │   └── mainscene.nim
│   ├── demo5/
│   │   ├── README.md
│   │   ├── cursor.nim
│   │   ├── demo5.nim
│   │   ├── earth.nim
│   │   ├── line.nim
│   │   ├── mainscene.nim
│   │   ├── poly1.nim
│   │   ├── poly2.nim
│   │   ├── poly3.nim
│   │   ├── poly9.nim
│   │   └── spaceman.nim
│   ├── demo6/
│   │   ├── README.md
│   │   ├── demo6.nim
│   │   ├── earth.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo7/
│   │   ├── README.md
│   │   ├── demo7.nim
│   │   ├── earth.nim
│   │   └── mainscene.nim
│   ├── demo8/
│   │   ├── README.md
│   │   ├── demo8.nim
│   │   └── mainscene.nim
│   ├── demo9/
│   │   ├── README.md
│   │   ├── demo9.nim
│   │   └── mainscene.nim
│   └── nim.cfg
├── docs/
│   ├── changelog.html
│   ├── demos.html
│   ├── docs/
│   │   ├── assets.html
│   │   ├── audio.html
│   │   ├── bitmapfont.html
│   │   ├── count.html
│   │   ├── draw.html
│   │   ├── emitter.html
│   │   ├── entity.html
│   │   ├── font.html
│   │   ├── graphic.html
│   │   ├── gui/
│   │   │   ├── button.html
│   │   │   ├── progressbar.html
│   │   │   ├── radio.html
│   │   │   ├── textinput.html
│   │   │   └── widget.html
│   │   ├── indexedimage.html
│   │   ├── input.html
│   │   ├── mosaic.html
│   │   ├── nimgame.html
│   │   ├── perspectiveimage.html
│   │   ├── plugin/
│   │   │   ├── mpeggraphic.html
│   │   │   ├── tar.html
│   │   │   └── zzip.html
│   │   ├── private/
│   │   │   └── collider.html
│   │   ├── procgraphic.html
│   │   ├── scene.html
│   │   ├── settings.html
│   │   ├── textfield.html
│   │   ├── textgraphic.html
│   │   ├── textureatlas.html
│   │   ├── texturegraphic.html
│   │   ├── tilemap.html
│   │   ├── truetypefont.html
│   │   ├── tween.html
│   │   ├── types.html
│   │   ├── typewriter.html
│   │   └── utils.html
│   ├── docs.html
│   ├── index.html
│   ├── links.html
│   ├── snippets.html
│   ├── structure.js
│   ├── style.css
│   ├── template.html
│   ├── template_tutorial.html
│   ├── tut101_bounce.html
│   ├── tut102_platformer.html
│   └── tutorials.html
├── nimgame2/
│   ├── assets.nim
│   ├── audio.nim
│   ├── bitmapfont.nim
│   ├── draw.nim
│   ├── emitter.nim
│   ├── entity.nim
│   ├── font.nim
│   ├── graphic.nim
│   ├── gui/
│   │   ├── button.nim
│   │   ├── progressbar.nim
│   │   ├── radio.nim
│   │   ├── textinput.nim
│   │   └── widget.nim
│   ├── indexedimage.nim
│   ├── input.nim
│   ├── mosaic.nim
│   ├── nimgame.nim
│   ├── perspectiveimage.nim
│   ├── plugin/
│   │   ├── mpeggraphic.nim
│   │   ├── tar.nim
│   │   └── zzip.nim
│   ├── private/
│   │   └── collider.nim
│   ├── procgraphic.nim
│   ├── scene.nim
│   ├── settings.nim
│   ├── textfield.nim
│   ├── textgraphic.nim
│   ├── textureatlas.nim
│   ├── texturegraphic.nim
│   ├── tilemap.nim
│   ├── truetypefont.nim
│   ├── tween.nim
│   ├── types.nim
│   ├── typewriter.nim
│   └── utils.nim
├── nimgame2.nim
└── nimgame2.nimble

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
# nimgame2
# Copyright (c) 2016-2020 Vladimir Arabadzhi (Vladar)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# vladar4@gmail.com
# https://github.com/Vladar4



================================================
FILE: README.md
================================================
Nimgame 2
=========

A simple 2D game engine for Nim language.

For more information check [home page](https://vladar4.github.io/nimgame2/).

[Coding style guide](STYLE.md) for the contributors.

All pull requests should be done into the **devel** branch.

Status: v0.6.2 alpha
--------------------


Requires:
---------

* [sdl2_nim](https://github.com/Vladar4/sdl2_nim) package (v2.0.14.2 or newer).
* Runtime libraries for:
  * SDL 2.0.12 or newer
  * SDL_gfx 1.0.1
  * SDL_image 2.0.2
  * SDL_mixer 2.0.2
  * SDL_ttf 2.0.14
(see [SDL2 links](https://github.com/Vladar4/sdl2_nim/blob/master/LINKS.md))


Optional dependencies:
----------------------

* For plugin/mpeggraphic
  * mpg123 runtime library (dll is distributed within SDL_)
* For plugin/tar:
  * [zip](https://github.com/nim-lang/zip)
  * zlib runtime library (dll is distributed within SDL2_image builds)
* For plugin/zzip:
  * [zip](https://github.com/nim-lang/zip)
  * zlib runtime library (dll is distributed within SDL2_image builds)
  * zzip runtime library


Installation through [Nimble](https://github.com/nim-lang/nimble):
------------------------------------------------------------------

* stable version: `nimble install nimgame2@#head`
* development version: `nimble install nimgame2@#devel`


Recommended compilation flags:
------------------------------
`--multimethods:on -d:release --opt:speed`


Links:
------

* [home page](https://vladar4.github.io/nimgame2/)
* [demos](demos)
* [tutorials](https://vladar4.github.io/nimgame2/tutorials)
* [documentation](https://vladar4.github.io/nimgame2/docs.html)
* [ng2planetoids](https://github.com/Vladar4/ng2planetoids) - first demo game.
* [ng2gggrotto](https://github.com/Vladar4/ng2gggrotto) - Linux Game Jam 2017 entry.


Changelog:
----------

### v0.6.2 alpha (2021-08-20)
* Maintenance release to keep up with the current versions of Nim and sdl2_nim until v0.7 is ready

### v0.6.1 alpha (2019-06-15)
* Nim v0.20.0 transition

### v0.6 alpha (2019-01-21)
* new modules: typewriter
* new plugins: mpeggraphic (+demo22), tar, zzip
* new utils procedures: textureFormat, textureFormats, toSeq, neg, new rand procedures
* color constants
* audio: playing template
* emitter: emission areas, procedure argument for emit
* entity: animation callback, blinking, scale parameters, dim template (by [CodeDoes](https://github.com/CodeDoes))
* input: mouse wheel events (by [CodeDoes](https://github.com/CodeDoes))
* icon surface init option
* RW loading procedures
* simplified time counters
* demo23 (transform) (by [CodeDoes](https://github.com/CodeDoes))
* various minor changes and upgrades, code refactoring
* Nim v0.19.0 transition


### v0.5 alpha (2017-08-01)
* changed physics and logic systems
* platformer physics
* CoordInt type
* now collider module is autmatically included into the entity module
* group collider
* huge Tilemap optimizations
* various utility Tilemap procedures
* TextureGraphic.drawTiled
* GUI:
  * GUIProgressBar
  * widget actions
* various minor changes and upgrades
* Nim v0.17.0 transition
* documentation, snippets, and demos update
* [second tutorial](https://vladar4.github.io/nimgame2/tut102_platformer.html)

### v0.4 alpha (2017-05-04)
* GUI:
  * RadioGroup
  * RadioButton
* IndexedImage
* PerspectiveImage
* TextureAtlas
* joysticks support
* window management procedures
* 4 new demos
* [first tutorial](https://vladar4.github.io/nimgame2/tut101_bounce.html)


### v0.3 alpha (2017-03-10)
* camera property (Scene)
* new collision procedures
* reworked input
* Mosaic
* parallax property (Entity)
* TextField
* GUI:
  * Widget
  * Button
  * TextInput
* 3 new demos
* home page, snippets, and documentation

### v0.2 alpha (2017-01-31)
* collider optimizations
* music playlists
* random procedures
* tilemaps
* tweens
* emitters
* various fixes
* 4 new demos

### v0.1 alpha (2017-01-16)
* base scene/entity system
* assets manager
* basic sound and music
* colliders (point, box, circle, line, and polygon)
* fonts (bitmap and TrueType) and text output
* keyboard and mouse input
* vector drawing procedures



================================================
FILE: STYLE.md
================================================
Nimgame 2 code formatting style
===============================

In general, follow [NEP1](https://nim-lang.org/docs/nep1.html) if it doesn't contradict this document.


Line Spacing
------------
* two empty lines before and one empty line after the header-comment;
* two empty lines between blocks (such as `const`, `type`, `proc`, etc.);
* one empty line to separate segments inside these blocks if needed;
* one empty line at the end of files.


Comments
--------

* if there is more than one type declared in one module, their procedures should be separated with header-comments:
  ```
  #==========#
  # SomeType #
  #==========#
  ```
* documentation comments are always offset by one indentation level inside their procedures, have two spaces before their text, and one empty comment line to separate it from the code below.
  ```
  proc someProc() =
    ##  Documentation comment.
    ##
    var someVar
    ...
  ```


Naming
------
* types and constants in PascalCase;
* all other identifiers in camelCase;
* if an object is a first argument of a procedure, generally it should be named after its type, e.g.:
  ```
  proc foo(bar: Bar, val: int): int =
  ```


Objects
-------
* private and public fields should be separated with comments if possible;
* `ref object` types should have the following initialization scheme:
  ```
  type SomeType = ref object of SomeParent
    someValue*: int


  proc initSomeType*(someType: SomeType) =
    someType.initSomeParent() # don't forget the parent initialization
    SomeType.someValue = 0
    ...


  proc newSomeType*(): SomeType =
    result = new SomeType
    result.initSomeType()
  ```
* types that are inherited from the `Entity` type should follow the following update scheme:
  ```
  type
    SomeEntity = ref object of Entity


  proc updateSomeEntity*(someEntity: SomeEntiy, elapsed: float) =
    someEntity.updateEntity(elapsed) # don't forget the parent update
    ...


  method update*(someEntity: SomeEntiy, elapsed: float) =
    updateSomeEntity(someEntity, elapsed)
  ```


Code
----
* don't forget proper spaces between elements;
* procedural arguments are separated by commas, e.g.:
  ```
  proc someProc(arg1: int, arg2, arg3: float): float =
  ```
* if there are a lot of arguments, they could be brought to a new line and indented by two levels for the sake of readability, e.g.:
  ```
  proc someLongAndComplexProcedure(
      arg1, arg2, arg3, arg4: int
      arg5, arg6, arg7, arg8: float) =
    ## Documentation
    ##
    ...
  ```


Example
-------
  ```
  # Header

  type
    SomeType1 = object
      # Private
      fHidden: int
      # Public
      value*: int

    SomeType2 = object
      a, b*: float


  const
    SomeConst1 = 42


  proc someProc*(arg1: int): int =
    ...


  #===========#
  # SomeType1 #
  #===========#

  proc someProc1*(someType1: SomeType1, a, b: int) =
    ...


  #===========#
  # SomeType2 #
  #===========#

  ...

  ```



================================================
FILE: demos/README.md
================================================
Nimgame 2 Demos
===============

* [demo1](demo1) Performance

* [demo2](demo2) Graphic

* [demo3](demo3) Input

* [demo4](demo4) Sprite

* [demo5](demo5) Colliders

* [demo6](demo6) Grouping

* [demo7](demo7) Text

* [demo8](demo8) ProcGraphic

* [demo9](demo9) Audio

* [demo10](demo10) Layers

* [demo11](demo11) Tweens

* [demo12](demo12) Emitters

* [demo13](demo13) TileMaps

* [demo14](demo14) TileMaps, Tweens, Emitters

* [demo15](demo15) Camera

* [demo16](demo16) Parallax

* [demo17](demo17) GUI (Button, TextField)

* [demo18](demo18) IndexedImage

* [demo19](demo19) PerspectiveImage

* [demo20](demo20) TextureAtlas

* [demo21](demo21) Joysticks

* [demo22](demo22) MpegGraphic

* [demo23](demo23) Transform



================================================
FILE: demos/assets/csv/atlas.csv
================================================
spaceman, 12, 33, 42, 66
gradient, 65, 9, 16, 90
button, 82, 26, 48, 72
sprite, 132, 0, 68, 100


================================================
FILE: demos/assets/csv/map0.csv
================================================
0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,1,1,1,3,1,1,1,1,1,3,1,1,1,1,1,1,1,1,3,1,1,1,3
3,1,1,1,1,1,1,1,1,1,3,1,1,1,3,3,3,3,1,1,1,3,1,2,1,3
3,1,3,1,1,1,3,3,1,3,3,3,3,3,3,1,1,3,1,3,3,3,1,1,1,3
3,1,3,3,1,3,3,1,1,1,1,1,1,1,1,1,1,3,1,3,0,3,3,1,3,3
3,1,3,1,1,1,3,3,3,3,3,1,1,3,3,1,1,3,1,3,0,0,3,1,3,0
3,1,1,1,1,1,1,1,1,1,3,3,1,3,3,3,1,3,1,3,3,3,3,1,3,0
3,3,3,1,1,1,3,1,1,1,3,1,1,1,3,3,1,1,1,3,1,1,1,1,3,0
0,0,3,3,1,3,3,1,1,1,3,1,1,1,3,3,3,3,3,3,3,3,3,1,3,0
3,3,3,1,1,1,3,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,3,1,3,0
3,1,1,1,1,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,0
3,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3
3,1,3,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,1,1,1,1,1,1,1,3
3,1,1,1,1,1,1,1,3,1,3,3,1,1,1,3,1,3,1,3,3,3,3,3,1,3
3,3,3,1,3,1,1,1,3,1,3,3,1,1,1,3,1,3,1,3,1,1,1,3,1,3
0,0,3,1,3,1,3,3,3,1,3,3,1,1,1,1,1,3,1,3,1,1,1,1,1,3
3,3,3,3,3,1,3,3,1,1,1,3,3,3,3,3,1,3,1,3,1,1,1,3,1,3
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,3,3,1,3
3,1,1,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,3
3,3,3,3,0,0,0,3,3,3,3,3,0,0,0,0,0,3,3,3,3,3,3,3,3,3


================================================
FILE: demos/assets/csv/map_camera_test.csv
================================================
1,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,1
3,2,3,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,3,2,3
1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3,1,3,1,1,3,1,3,3
1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1,1,3,3,3,3,1,1,1
1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1
3,2,3,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,3,2,3
1,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,1


================================================
FILE: demos/demo1/README.md
================================================
Nimgame 2: Demo 1
=================

Performance demo.

![Screenshot](demo1.png)



================================================
FILE: demos/demo1/demo1.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 1 (Performance)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo1/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  spaceman


const
  NumMin = 100
  NumMax = 50_000
  NumStep = 100
  NumStart = 500


type
  MainScene = ref object of Scene
    spacemanG: TextureGraphic
    num: int


proc spacemanPhysics*(entity: Entity, elapsed: float) =
  defaultPhysics(entity, elapsed)

  # Screen collision
  if entity.pos.x < 0:
    entity.vel.x *= -1
  if entity.pos.y < 0:
    entity.vel.y *= -1
  if entity.pos.x >= game.size.w.float:
    entity.vel.x *= -1
  if entity.pos.y >= game.size.h.float:
    entity.vel.y *= -1


proc init*(scene: MainScene) =
  Scene(scene).init()
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")
  scene.num = NumStart
  for i in 1..scene.num:
    scene.add(newSpaceman(scene, scene.spacemanG, spacemanPhysics))


proc free*(scene: MainScene) =
  scene.spacemanG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Up:
      if scene.num < NumMax:
        scene.num += NumStep
        for i in scene.count..scene.num-1:
          scene.add(newSpaceman(scene, scene.spacemanG, spacemanPhysics))
    of K_Down:
      if scene.num > NumMin:
        scene.num -= NumStep
        for i in scene.num..(scene.count - 1):
          discard scene.pop()
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (260, 84), 0x000000CC'u32)
  discard string(
    (8, 64), "Arrow Up - more entities", 0xFF0000FF'u32)
  discard string(
    (8, 72), "Arrow Down - less entities", 0xFF0000FF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)



================================================
FILE: demos/demo1/spaceman.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/graphic,
  nimgame2/scene,
  nimgame2/types,
  nimgame2/utils

type
  Spaceman* = ref object of Entity
    scene*: Scene


proc init*(entity: Spaceman, s: Scene, g: Graphic, p: PhysicsProc) =
  entity.initEntity()
  entity.scene = s
  entity.graphic = g
  entity.physics = p
  entity.pos.x = rand(game.size.w).float
  entity.pos.y = rand(game.size.h).float
  entity.vel.x = rand(10.0..100.0) * randSign().float
  entity.vel.y = rand(10.0..100.0) * randSign().float
  entity.centrify()
  entity.rot = rand(360.0)
  entity.rotVel = rand(10.0..60.0) * randSign().float


proc newSpaceman*(s: Scene, g: Graphic, p: PhysicsProc): Spaceman =
  result = new Spaceman
  result.init(s, g, p)



================================================
FILE: demos/demo10/README.md
================================================
Nimgame 2: Demo 10
==================

Layers demo. Demonstrates entity layering.

![Screenshot](demo10.png)



================================================
FILE: demos/demo10/demo10.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 10 (Layers)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo10/earth.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Earth* = ref object of Entity


proc init*(entity: Earth) =
  entity.initEntity()
  entity.pos.x = 128.0
  entity.pos.y = 96.0


proc newEarth*(): Earth =
  result = new Earth
  result.init()



================================================
FILE: demos/demo10/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  earth, spaceman


type
  MainScene = ref object of Scene
    earthG, spacemanG: TextureGraphic
    e: Earth
    s: Spaceman


proc init*(scene: MainScene) =
  Scene(scene).init()
  # Earth
  scene.e = newEarth()
  scene.earthG = newTextureGraphic()
  discard scene.earthG.load("../assets/gfx/earth.png")
  scene.e.graphic = scene.earthG
  # Spaceman
  scene.s = newSpaceman()
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")
  scene.s.graphic = scene.spacemanG

  # add to scene
  scene.add(scene.s)
  scene.add(scene.e)


proc free*(scene: MainScene) =
  scene.earthG.free
  scene.spacemanG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (220, 76), 0x000000CC'u32)
  discard string(
    (8, 64), "1/2 - Change layer", 0xFF0000FF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if Scancode1.down: scene.s.layer = -1
  if Scancode2.down: scene.s.layer = 1



================================================
FILE: demos/demo10/spaceman.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Spaceman* = ref object of Entity


proc init*(entity: Spaceman) =
  entity.initEntity()
  entity.pos.x = 200.0
  entity.pos.y = 64.0


proc newSpaceman*(): Spaceman =
  result = new Spaceman
  result.init()



================================================
FILE: demos/demo11/README.md
================================================
Nimgame 2: Demo 11
==================

Tweens demo. Demonstrates tweening procedures.

![Screenshot](demo11.png)



================================================
FILE: demos/demo11/demo11.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 1280, h = 720, title = "Nimgame 2: Demo 11 (Tweens)"):
  #showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo11/earth.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/types

type
  Earth* = ref object of Entity


proc init*(entity: Earth, pos: Coord) =
  entity.initEntity()
  entity.pos = pos


proc newEarth*(pos: Coord): Earth =
  result = new Earth
  result.init(pos)



================================================
FILE: demos/demo11/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/bitmapfont,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/textgraphic,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/tween,
  nimgame2/types,
  earth


type
  MainScene = ref object of Scene
    earthG: TextureGraphic
    font: BitmapFont
    tweens: seq[Tween[Entity,Coord]]


proc addEntity*(scene: MainScene,
                name: string,
                pos: Coord,
                procedure: TweenProcedure[Coord]) =
  # Name
  let n = newTextGraphic()
  n.font = scene.font
  n.lines = [name]
  let ne = newEntity()
  ne.graphic = n
  ne.pos = pos - (98.0, 8.0)
  scene.add(ne)

  # Entity
  let e = newEarth(pos)
  e.graphic = scene.earthG
  e.centrify()
  scene.add(e)

  # Tween
  let t = newTween[Entity,Coord](
    e,
    proc(t: Entity): Coord = t.pos,
    proc(t: Entity, val: Coord) = t.pos = val)
  t.procedure = procedure
  scene.tweens.add(t)
  t.setup(e.pos, e.pos + (150.0, 0.0), 3.0, -1)
  t.play()


proc init*(scene: MainScene) =
  Scene(scene).init()
  scene.tweens = @[]

  # Earth graphic
  scene.earthG = newTextureGraphic()
  discard scene.earthG.load("../assets/gfx/earth32.png")

  # Font
  scene.font = newBitmapFont()
  discard scene.font.load("../assets/fnt/default8x16.png", (8, 16))

  # Column 1
  scene.addEntity("linear", (100.0, 35.0), linear)
  scene.addEntity("inQuad", (100.0, 85.0), inQuad)
  scene.addEntity("outQuad", (100.0, 135.0), outQuad)
  scene.addEntity("inOutQuad", (100.0, 185.0), inOutQuad)

  scene.addEntity("inCubic", (100.0, 285.0), inCubic)
  scene.addEntity("outCubic", (100.0, 335.0), outCubic)
  scene.addEntity("inOutCubic", (100.0, 385.0), inOutCubic)
  scene.addEntity("outInCubic", (100.0, 435.0), outInCubic)

  scene.addEntity("inQuart", (100.0, 535.0), inQuart)
  scene.addEntity("outQuart", (100.0, 585.0), outQuart)
  scene.addEntity("inOutQuart", (100.0, 635.0), inOutQuart)
  scene.addEntity("outInQuart", (100.0, 685.0), outInQuart)

  # Column 2
  scene.addEntity("inQuint", (400.0, 35.0), inQuint)
  scene.addEntity("outQuint", (400.0, 85.0), outQuint)
  scene.addEntity("inOutQuint", (400.0, 135.0), inOutQuint)
  scene.addEntity("outInQuint", (400.0, 185.0), outInQuint)

  scene.addEntity("inSine", (400.0, 285.0), inSine)
  scene.addEntity("outSine", (400.0, 335.0), outSine)
  scene.addEntity("inOutSine", (400.0, 385.0), inOutSine)
  scene.addEntity("outInSine", (400.0, 435.0), outInSine)

  # Column 3
  scene.addEntity("inExpo", (700.0, 35.0), inExpo)
  scene.addEntity("outExpo", (700.0, 85.0), outExpo)
  scene.addEntity("inOutExpo", (700.0, 135.0), inOutExpo)
  scene.addEntity("outInExpo", (700.0, 185.0), outInExpo)

  scene.addEntity("inCirc", (700.0, 285.0), inCirc)
  scene.addEntity("outCirc", (700.0, 335.0), outCirc)
  scene.addEntity("inOutCirc", (700.0, 385.0), inOutCirc)
  scene.addEntity("outInCirc", (700.0, 435.0), outInCirc)

  # Column 4
  scene.addEntity("inBounce", (1000.0, 35.0), inBounce)
  scene.addEntity("outBounce", (1000.0, 85.0), outBounce)
  scene.addEntity("inOutBounce", (1000.0, 135.0), inOutBounce)
  scene.addEntity("outInBounce", (1000.0, 185.0), outInBounce)

  scene.addEntity("inElastic", (1000.0, 285.0), inElastic)
  scene.addEntity("outElastic", (1000.0, 335.0), outElastic)
  scene.addEntity("inOutElastic", (1000.0, 385.0), inOutElastic)
  scene.addEntity("outInElastic", (1000.0, 435.0), outInElastic)

  scene.addEntity("inBack", (1000.0, 535.0), inBack)
  scene.addEntity("outBack", (1000.0, 585.0), outBack)
  scene.addEntity("inOutBack", (1000.0, 635.0), inOutBack)
  scene.addEntity("outInBack", (1000.0, 685.0), outInBack)


proc free*(scene: MainScene) =
  scene.earthG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()


method update*(scene: MainScene, elapsed: float) =
  for tween in scene.tweens:
    tween.update(elapsed)
  scene.updateScene(elapsed)



================================================
FILE: demos/demo12/README.md
================================================
Nimgame 2: Demo 12
==================

Emitter demo. Demonstrates particle emitter usage.

![Screenshot](demo12.png)



================================================
FILE: demos/demo12/demo12.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 12 (Emitter)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo12/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/emitter,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types


type
  MainScene = ref object of Scene
    particleG: TextureGraphic
    ePoint, eLine, eCircle, eBox, eScaled: Emitter


proc init*(scene: MainScene) =
  Scene(scene).init()
  # Particle Graphic
  scene.particleG = newTextureGraphic()
  discard scene.particleG.load("../assets/gfx/puff.png")

  # Particle
  var particle: Particle
  particle = newParticle()
  particle.graphic = scene.particleG
  particle.initSprite((5, 5))
  particle.centrify()
  discard particle.addAnimation("play", toSeq(0..4), 1/5)
  particle.play("play", 1, kill = true)

  # Point emitter
  scene.ePoint = newEmitter(scene)
  scene.ePoint.randomVel = (10.0, 10.0)
  scene.ePoint.randomAcc = (5.0, 5.0)
  scene.ePoint.randomTTL = 5.0
  scene.ePoint.particle = particle
  scene.add(scene.ePoint)

  # Line emitter
  scene.eLine = newEmitter(scene, eaLine)
  scene.eLine.area.length = 100.0
  scene.eLine.randomVel = (10.0, 10.0)
  scene.eLine.randomAcc = (5.0, 5.0)
  scene.eLine.randomTTL = 5.0
  scene.eLine.particle = particle
  scene.eLine.pos = game.size / 2
  scene.add(scene.eLine)

  # Circle emitter
  scene.eCircle = newEmitter(scene, eaCircle)
  scene.eCircle.area.radius = 100.0
  scene.eCircle.randomVel = (10.0, 10.0)
  scene.eCircle.randomAcc = (5.0, 5.0)
  scene.eCircle.randomTTL = 5.0
  scene.eCircle.particle = particle
  scene.eCircle.pos = game.size / 4
  scene.add(scene.eCircle)

  # Box emitter
  scene.eBox = newEmitter(scene, eaBox)
  scene.eBox.area.dim = (100.0, 50.0)
  scene.eBox.rotVel = -90.0
  scene.eBox.randomVel = (10.0, 10.0)
  scene.eBox.randomAcc = (5.0, 5.0)
  scene.eBox.randomTTL = 5.0
  scene.eBox.particle = particle
  scene.eBox.pos = game.size / 2 + game.size / 4
  scene.add(scene.eBox)

  # Scaling particles
  var particleScaled: Particle
  particleScaled = newParticle()
  particleScaled.graphic = scene.particleG
  particleScaled.initSprite((5, 5))
  particleScaled.centrify()
  discard particleScaled.addAnimation("play", toSeq(0..4), 1/2)
  particleScaled.play("play", 1, kill = true)
  particleScaled.scale = 0.5
  particleScaled.scaleVel = 1.0

  scene.eScaled = newEmitter(scene)
  scene.eScaled.randomVel = (50.0, 50.0)
  scene.eScaled.randomAcc = (5.0, 5.0)
  scene.eScaled.randomTTL = 5.0
  scene.eScaled.particle = particleScaled
  scene.eScaled.pos = (game.size.w div 2 + game.size.w div 4, game.size.h div 4)
  scene.add(scene.eScaled)



proc free*(scene: MainScene) =
  scene.particleG.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  # Draw line between the spaceman and the mouse position if LMB is pressed
  scene.renderScene()


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  # Point emitter
  scene.ePoint.pos = mouse.abs
  if MouseButton.left.down:
    scene.ePoint.emit(5)
  # Line emitter
  scene.eLine.rot += 90 * elapsed
  scene.eLine.emit(5)
  # Circle emitter
  scene.eCircle.area.radius = if MouseButton.left.down: 50.0 else: 100.0
  scene.eCircle.emit(scene.eCircle.area.radius.int div 20)
  # Box emitter
  scene.eBox.rot += scene.eBox.rotVel * elapsed
  scene.eBox.emit(5)
  # Scaled emitter
  scene.eScaled.emit(5)



================================================
FILE: demos/demo13/README.md
================================================
Nimgame 2: Demo 13
==================

TileMap demo. Demonstrates tile maps usage.

Note
----
For the performance purposes TileCollider is based on BoxCollider. It means, that usually you shouldn't initialize collider on a TileMap that will be rotated.

![Screenshot](demo13.png)



================================================
FILE: demos/demo13/cursor.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/input,
  nimgame2/tilemap

type
  Cursor* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Cursor) =
  entity.initEntity()
  entity.tags.add("Cursor")
  entity.pos = mouse.abs
  entity.collidedWith = @[]


proc newCursor*(): Cursor =
  result = new Cursor
  result.init()


method update*(entity: Cursor, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]
  entity.pos = mouse.abs


method onCollide*(entity: Cursor, target: Entity) =
  if target.tags.len > 0:
    if "map" in target.tags:
      let collider = TilemapCollider(target.collider)
      let clist = collider.collisionList(entity.pos)
      for tile in clist:
        entity.collidedWith.add(
          "[" & $tile.index.x & ":" & $tile.index.y & "] -> " & $tile.value)



================================================
FILE: demos/demo13/demo13.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 13 (TileMap)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo13/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/tilemap,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  cursor


type
  MainScene = ref object of Scene
    tilesG: TextureGraphic
    tm: TileMap
    cursor: Cursor


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Cursor
  hideCursor()
  scene.cursor = newCursor()
  let cursorG = newTextureGraphic()
  discard cursorG.load("../assets/gfx/cursor.png")
  scene.cursor.graphic = cursorG
  scene.cursor.collider = newCollider(scene.cursor)
  scene.add(scene.cursor)

  # Tiles Graphic
  scene.tilesG = newTextureGraphic()
  discard scene.tilesG.load("../assets/gfx/sprite0.png")
  # TileMap
  scene.tm = newTileMap(scaleFix = true)
  scene.tm.tags.add("map")
  scene.tm.graphic = scene.tilesG
  scene.tm.initSprite((64, 64), offset = (32, 32))
  scene.tm.map = @[
    @[0, 0, 0, 0],
    @[1, 0, 0, 1],
    @[2, 3, 3, 2]
  ]
  scene.tm.passable.add(0)
  scene.tm.centrify()
  scene.tm.initCollider()
  scene.tm.pos = (320.0, 240.0)
  scene.add(scene.tm)



proc free*(scene: MainScene) =
  scene.tilesG.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      colliderOutline = not colliderOutline
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (300, 108), 0x000000CC'u32)

  discard string((8, 64), "WSAD or Arrows - move", 0xFFFFFFFF'u32)

  discard string((8, 72), "Q/E - change angle", 0xFFFFFFFF'u32)

  discard string((8, 80), "R/F - change scale", 0xFFFFFFFF'u32)

  discard string((8, 88), "Space - toggle collider outlines", 0xFFFFFFFF'u32)

  var collides: string = ""
  for collision in scene.cursor.collidedWith:
    collides &= collision & " "

  discard string((8, 96),
    if scene.cursor.collidedWith.len > 0:
      "Cursor collides with: " & collides
    else:
      "Cursor isn't over a collidable tile",
    0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if ScancodeW.down or ScancodeUp.down: scene.tm.pos.y -= 100 * elapsed
  if ScancodeS.down or ScancodeDown.down: scene.tm.pos.y += 100 * elapsed
  if ScancodeA.down or ScancodeLeft.down: scene.tm.pos.x -= 100 * elapsed
  if ScancodeD.down or ScancodeRight.down: scene.tm.pos.x += 100 * elapsed
  if ScancodeQ.down: scene.tm.rot -= 100 * elapsed
  if ScancodeE.down: scene.tm.rot += 100 * elapsed
  if ScancodeR.down: scene.tm.scale -= 0.5 * elapsed
  if ScancodeF.down: scene.tm.scale += 0.5 * elapsed



================================================
FILE: demos/demo14/README.md
================================================
Nimgame 2: Demo 14
==================

Second TileMap demo. Demonstrates practical TileMap usage, along with Tween an Emitter usage.

F10 - Show/Hide info panel.

![Screenshot](demo14.png)



================================================
FILE: demos/demo14/demo14.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 14 (TileMap 2)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo14/dwarf.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/tilemap,
  nimgame2/tween,
  nimgame2/types


const
  Framerate = 1/12
  ScreenOffset*: Coord = (8.0, 0.0)
  Step* = 24.0


type
  Direction* = enum dNone, dDown, dUp, dLeft, dRight

  Dwarf* = ref object of Entity
    tween*: Tween[Dwarf,Coord]
    virtualPos*: tuple[x: int, y: int]
    map*: TileMap


proc init*(entity: Dwarf, graphic: TextureGraphic, map: TileMap) =
  entity.initEntity()
  entity.tags.add("dwarf")
  entity.graphic = graphic
  entity.initSprite((24, 48))
  discard entity.addAnimation(
    "down", [0, 1, 2, 3, 4, 5], Framerate)
  discard entity.addAnimation(
    "up", [6, 7, 8, 9, 10, 11], Framerate)
  discard entity.addAnimation(
    "left", [12, 13, 14, 15, 16, 17], Framerate)
  discard entity.addAnimation(
    "right", [12, 13, 14, 15, 16, 17], Framerate, Flip.horizontal)
  entity.pos = (44.0, 444.0)
  entity.virtualPos = (1, 18)
  entity.center = (12.0, 36.0)
  entity.map = map
  entity.map.show = (
    x: (entity.virtualPos.x - 2)..(entity.virtualPos.x + 2),
    y: (entity.virtualPos.y - 2)..(entity.virtualPos.y + 2)
  )


proc newDwarf*(graphic: TextureGraphic, map: TileMap): Dwarf =
  result = new Dwarf
  result.init(graphic, map)


proc actuate(entity: Dwarf, anim: string, movement: Coord) =
  if entity.tween == nil or not entity.tween.playing:
    let
      newPos = entity.pos + movement
      newVirtualPos: tuple[x: int, y: int] =
        (int(newPos.x - ScreenOffset.x) div Step.int,
         int(newPos.y - ScreenOffset.y) div Step.int)

    if entity.map.map[newVirtualPos.y][newVirtualPos.x] > 2:
      return # unpassable

    entity.play(anim, 1)
    entity.tween = newTween[Dwarf,Coord](
      entity,
      proc(t: Dwarf): Coord = t.pos,
      proc(t: Dwarf, val: Coord) = t.pos = val)
    entity.tween.setup(entity.pos, newPos, 0.5, 0)
    entity.virtualPos = newVirtualPos
    entity.tween.play()
    entity.map.show = (
      x: (newVirtualPos.x - 2)..(newVirtualPos.x + 2),
      y: (newVirtualPos.y - 2)..(newVirtualPos.y + 2)
    )


proc move*(entity: Dwarf, direction: Direction) =
  case direction:
  of dDown:   entity.actuate("down", (0.0, Step))
  of dUp:     entity.actuate("up", (0.0, -Step))
  of dRight:  entity.actuate("right", (Step, 0.0))
  of dLeft:   entity.actuate("left", (-Step, 0.0))
  of dNone:   discard



================================================
FILE: demos/demo14/mainscene.nim
================================================
import
  parseutils,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/emitter,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/tilemap,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/tween,
  nimgame2/types,
  nimgame2/utils,
  dwarf


type
  MainScene = ref object of Scene
    dG, tilesG, sparkG: TextureGraphic
    d: Dwarf
    sparks: Emitter
    map: TileMap


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Spark
  scene.sparkG = newTextureGraphic()
  discard scene.sparkG.load("../assets/gfx/puff.png")

  # TileMap
  scene.tilesG = newTextureGraphic()
  discard scene.tilesG.load("../assets/gfx/tile0.png")
  scene.map = newTileMap()
  scene.map.tags.add("map")
  scene.map.graphic = scene.tilesG
  scene.map.initSprite((24, 24))
  scene.map.map = loadCSV[int](
    "../assets/csv/map0.csv",
    proc(input: string): int = discard parseInt(input, result))
  scene.map.pos = (8.0, 0.0)

  # Dwarf
  scene.dG = newTextureGraphic()
  discard scene.dG.load("../assets/gfx/dwarf.png")
  scene.d = newDwarf(scene.dG, scene.map)
  scene.d.layer = 10

  # Add to scene
  scene.add(scene.d)
  scene.add(scene.map)

proc free*(scene: MainScene) =
  scene.dG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
      case event.key.keysym.sym:
      of K_Escape:
        gameRunning = false
      of K_F10:
        showInfo = not showInfo
      else: discard


method render*(scene: MainScene) =
  scene.renderScene()


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if scene.d.tween != nil:
    scene.d.tween.update(elapsed)

  # Controls and speed
  var direction: dwarf.Direction =
    if ScancodeDown.down or ScancodeS.down: dDown
    elif ScancodeUp.down or ScancodeW.down: dUp
    elif ScancodeLeft.down or ScancodeA.down: dLeft
    elif ScancodeRight.down or ScancodeD.down: dRight
    else: dNone

  scene.d.move(direction)

  # Sparks
  if scene.sparks == nil:
    if scene.map.map[scene.d.virtualPos.y][scene.d.virtualPos.x] == 2:
      scene.sparks = newEmitter(scene)
      scene.sparks.pos = ((scene.d.virtualPos.x.float,
                           scene.d.virtualPos.y.float) * Step) +
                           ScreenOffset + scene.d.center - (0.0, Step)
      scene.sparks.randomVel = (25.0, 25.0)
      scene.sparks.randomAcc = (10.0, 10.0)
      scene.sparks.randomTTL = 2.5
      scene.sparks.particle = newParticle()
      scene.sparks.particle.graphic = scene.sparkG
      scene.sparks.particle.initSprite((5, 5))
      scene.sparks.particle.centrify()
      discard scene.sparks.particle.addAnimation("play", toSeq(0..4), 1/5)
      scene.sparks.particle.play("play", 1, kill = true)
      scene.add(scene.sparks)
  else:
    scene.sparks.emit(10)




================================================
FILE: demos/demo15/README.md
================================================
Nimgame 2: Demo 15
==================

Camera demo. Demonstrates camera usage.

Note a negative sign in front of the camera's position.

![Screenshot](demo15.png)



================================================
FILE: demos/demo15/demo15.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 15 (Camera)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo15/mainscene.nim
================================================
import
  parseutils,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/tilemap,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  nimgame2/utils


type
  MainScene = ref object of Scene
    tilesG, spacemanG: TextureGraphic
    spaceman: Entity
    map: TileMap


proc init*(scene: MainScene) =
  Scene(scene).init()

  scene.camera = newEntity()
  scene.cameraBondOffset = game.size / 2

  # Tiles Graphic
  scene.tilesG = newTextureGraphic()
  discard scene.tilesG.load("../assets/gfx/tile0.png")

  # TileMap
  scene.map = newTileMap(scaleFix = true)
  scene.map.parent = scene.camera
  scene.map.tags.add("map")
  scene.map.graphic = scene.tilesG
  scene.map.initSprite((24, 24))
  scene.map.map = loadCSV[int]("../assets/csv/map_camera_test.csv",
    proc(s: string): int = discard parseInt(s, result))
  scene.map.passable.add(0)
  scene.map.initCollider()
  scene.map.pos = (0.0, 0.0)

  # SpacemanG
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")

  # Spaceman
  scene.spaceman = newEntity()
  scene.spaceman.parent = scene.map
  scene.spaceman.graphic = scene.spacemanG
  scene.spaceman.centrify()
  scene.spaceman.pos = (200.0, 200.0)

  # Add
  scene.add(scene.spaceman)
  scene.add(scene.map)



proc free*(scene: MainScene) =
  scene.tilesG.free()
  scene.spacemanG.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      colliderOutline = not colliderOutline
    of K_Return:
      scene.cameraBond = if scene.cameraBond != nil: nil
                         else: scene.spaceman
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (300, 108), 0x000000CC'u32)

  discard string((8, 64), "Arrows - move camera", 0xFFFFFFFF'u32)
  discard string((8, 72), "WSAD - move spaceman", 0xFFFFFFFF'u32)
  discard string((8, 80), "Enter - toggle following (" &
    (if scene.cameraBond != nil: "on" else: "off")  & ")", 0xFFFFFFFF'u32)

  discard string((8, 88), "camera.pos = " & $(-scene.camera.pos),
    0xFFFFFFFF'u32)
  discard string((8, 96), "spaceman.pos = " & $(scene.spaceman.pos),
    0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  let move = 100 * elapsed
  if scene.cameraBond == nil:
    if ScancodeUp.down: scene.camera.pos.y += move
    if ScancodeDown.down: scene.camera.pos.y -= move
    if ScancodeLeft.down: scene.camera.pos.x += move
    if ScancodeRight.down: scene.camera.pos.x -= move
  if ScancodeW.down: scene.spaceman.pos.y -= move
  if ScancodeS.down: scene.spaceman.pos.y += move
  if ScancodeA.down: scene.spaceman.pos.x -= move
  if ScancodeD.down: scene.spaceman.pos.x += move



================================================
FILE: demos/demo16/README.md
================================================
Nimgame 2: Demo 16
==================

Parallax demo. Demonstrates parallax effect.

![Screenshot](demo16.png)



================================================
FILE: demos/demo16/demo16.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 16 (Parallax)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo16/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types


type
  MainScene = ref object of Scene
    spacemanG: TextureGraphic
    p0125, p025, p05, p1: Entity


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Graphics
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")

  # Entities
  scene.camera = newEntity()
  scene.camera.pos = game.size / 2

  scene.p0125 = newEntity()
  scene.p0125.parent = scene.camera
  scene.p0125.graphic = scene.spacemanG
  scene.p0125.centrify()
  scene.p0125.pos = game.size / 2
  scene.p0125.pos.y -= 150
  scene.p0125.parallax = 0.125

  scene.p025 = newEntity()
  scene.p025.parent = scene.camera
  scene.p025.graphic = scene.spacemanG
  scene.p025.centrify()
  scene.p025.pos = game.size / 2
  scene.p025.pos.y -= 100
  scene.p025.parallax = 0.25

  scene.p05 = newEntity()
  scene.p05.parent = scene.camera
  scene.p05.graphic = scene.spacemanG
  scene.p05.centrify()
  scene.p05.pos = game.size / 2
  scene.p05.pos.y -= 50
  scene.p05.parallax = 0.5

  scene.p1 = newEntity()
  scene.p1.parent = scene.camera
  scene.p1.graphic = scene.spacemanG
  scene.p1.centrify()
  scene.p1.pos = game.size / 2

  scene.cameraBond = scene.p1

  # add to scene
  scene.add(scene.p1)
  scene.add(scene.p05)
  scene.add(scene.p025)
  scene.add(scene.p0125)


proc free*(scene: MainScene) =
  scene.spacemanG.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  scene.eventScene(event)
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      colliderOutline = not colliderOutline
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  scene.camera.pos = mouse.abs - Coord(game.size / 2)



================================================
FILE: demos/demo17/README.md
================================================
Nimgame 2: Demo 17
==================

First GUI demo. Demonstrates buttons and text field usage.

![Screenshot](demo17.png)



================================================
FILE: demos/demo17/btnCircle.nim
================================================
import
  nimgame2/graphic,
  nimgame2/input,
  nimgame2/gui/widget,
  nimgame2/gui/button


type
  CircleButton* = ref object of GuiButton


proc init*(btn: CircleButton, graphic: Graphic) =
  GuiButton(btn).init(graphic, circle = true)


proc newCircleButton*(graphic: Graphic): CircleButton =
  new result
  result.init(graphic)


method onClick*(btn: CircleButton, mb: MouseButton) =
  echo "clicked circle button, toggled " & (if btn.toggled: "on" else: "off")



================================================
FILE: demos/demo17/btnSquare.nim
================================================
import
  nimgame2/graphic,
  nimgame2/input,
  nimgame2/gui/button


type
  SquareButton* = ref object of GuiButton


proc init*(btn: SquareButton, graphic: Graphic, image: Graphic = nil) =
  GuiButton(btn).init(graphic, image)


proc newSquareButton*(graphic: Graphic, image: Graphic = nil): SquareButton =
  new result
  result.init(graphic, image)


method onClick*(btn: SquareButton, mb: MouseButton) =
  echo "clicked square button"



================================================
FILE: demos/demo17/demo17.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 17 (GUI)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo17/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/mosaic,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/truetypefont,
  nimgame2/types,
  nimgame2/gui/widget,
  nimgame2/gui/radio,
  nimgame2/gui/textinput,
  nimgame2/gui/progressbar,
  btnSquare, btnCircle


type
  MainScene = ref object of Scene
    btnSquareG, btnCircleG, iconX, btnMosaicG, inputG: TextureGraphic
    btnsRadio: array[3, GuiRadioButton]
    radioGroup: GuiRadioGroup
    btnSquare, btnMosaic: SquareButton
    btnCircle: CircleButton
    textInput: GuiTextInput
    progressBar: GuiProgressBar
    font: TrueTypeFont


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Graphics
  scene.btnSquareG = newTextureGraphic()
  discard scene.btnSquareG.load("../assets/gfx/button_square.png")
  scene.btnCircleG = newTextureGraphic()
  discard scene.btnCircleG.load("../assets/gfx/button_circle.png")
  scene.iconX = newTextureGraphic()
  discard scene.iconX.load("../assets/gfx/icon_x.png")
  let mosaic = newMosaic("../assets/gfx/button_square.png", (8, 8))
  scene.btnMosaicG = newTextureGraphic()
  discard scene.btnMosaicG.assignTexture mosaic.render(
    patternStretchBorder(4, 2))

  # Square Button
  scene.btnSquare = newSquareButton(scene.btnSquareG, scene.iconX)
  scene.btnSquare.mbAllow.set(MouseButton.right)
  scene.btnSquare.pos = (100, 100)
  # Circle Button
  scene.btnCircle = newCircleButton(scene.btnCircleG)
  scene.btnCircle.pos = (150, 100)
  scene.btnCircle.toggle = true
  # Mosaic Button
  scene.btnMosaic = newSquareButton(scene.btnMosaicG)
  scene.btnMosaic.pos = (200, 100)

  # Text Input
  scene.font = newTrueTypeFont()
  discard scene.font.load("../assets/fnt/FSEX300.ttf", 16)
  let inputmosaic = newMosaic("../assets/gfx/text_input.png", (8, 8))
  scene.inputG = newTextureGraphic()
  discard scene.inputG.assignTexture inputmosaic.render(
    patternStretchBorder(16, 1))
  scene.textInput = newGuiTextInput(scene.inputG, scene.font)
  scene.textInput.pos = (100, 150)
  scene.textInput.text.limit = 16

  # Radio Button
  scene.radioGroup = newGuiRadioGroup()
  scene.radioGroup.pos = (100, 200)
  for i in 0..scene.btnsRadio.high:
    scene.btnsRadio[i] = newGuiRadioButton(
      scene.radioGroup, scene.btnCircleG, circle = true)
    scene.btnsRadio[i].pos = (i.float * 50.0, 0.0)
  scene.btnsRadio[0].toggled = true

  # Progress Bar
  scene.progressBar = newProgressBar((200, 50), 0xFF0000FF'u32, 0x00FF00FF'u32,
    scene.font)
  scene.progressBar.min = 0
  scene.progressBar.max = 100
  scene.progressBar.value = 0
  scene.progressBar.direction = Direction.leftRight
  scene.progressBar.outline = (1, 1)
  scene.progressBar.pos = (100, 250)

  # add to scene
  scene.add(scene.progressBar)
  scene.add(scene.radioGroup)
  for b in scene.btnsRadio:
    scene.add(b)
  scene.add(scene.textInput)
  scene.add(scene.btnMosaic)
  scene.add(scene.btnSquare)
  scene.add(scene.btnCircle)


proc free*(scene: MainScene) =
  scene.inputG.free()
  scene.btnMosaicG.free()
  scene.btnSquareG.free()
  scene.btnCircleG.free()
  scene.iconX.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  scene.eventScene(event)
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      colliderOutline = not colliderOutline
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (220, 76), 0x000000CC'u32)
  discard string(
    (8, 64), "Space - toggle collider outlines", 0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)

  # progressBar
  if scene.progressBar.value < scene.progressBar.max:
    scene.progressBar.value += 10 * elapsed
    if scene.progressBar.value > scene.progressBar.max:
      scene.progressBar.value = scene.progressBar.max




================================================
FILE: demos/demo18/README.md
================================================
Nimgame 2: Demo 18
==================

IndexedImage. Demonstrates palette swapping in indexed images.

![Screenshot](demo18.png)



================================================
FILE: demos/demo18/demo18.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 320, h = 240, title = "Nimgame 2: Demo 18 (IndexedImage)"):
  game.windowSize = (640, 480)
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo18/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/indexedimage,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types


type
  MainScene = ref object of Scene
    idximg: IndexedImage
    knightG: TextureGraphic
    knight: Entity


proc init*(scene: MainScene) =
  Scene(scene).init()

  scene.idximg = newIndexedImage("../assets/gfx/knight.gif")

  scene.knightG = newTextureGraphic()
  discard scene.knightG.assignTexture scene.idximg.render()

  scene.knight = newEntity()
  scene.knight.graphic = scene.knightG
  scene.knight.pos = (128, 128)

  # add to scene
  scene.add(scene.knight)


proc free*(scene: MainScene) =
  scene.knightG.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  scene.eventScene(event)
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (220, 76), 0x000000CC'u32)
  discard string(
    (8, 64), "QWER - increase RGBA values (1st color)", 0xFFFFFFFF'u32)
  discard string(
    (8, 72), "ASDF - decrease RGBA values (1st color)", 0xFFFFFFFF'u32)
  discard string(
    (8, 80), "TYUI - increase RGBA values (2nd color)", 0xFFFFFFFF'u32)
  discard string(
    (8, 88), "GHJK - decrease RGBA values (2nd color)", 0xFFFFFFFF'u32)
  discard string(
    (8, 96), "1st: " & $scene.idximg.palette[3], 0xFFFFFFFF'u32)
  discard string(
    (8, 104), "2nd: " & $scene.idximg.palette[11], 0xFFFFFFFF'u32)


const
  Step = 15


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  let palette = scene.idximg.palette
  var
    upd = false
    color1 = palette[3]
    color2 = palette[11]

  # color1
  if ScancodeQ.pressed:
    color1.r = clamp(color1.r.int + Step, 0, 255).uint8
    upd = true
  if ScancodeW.pressed:
    color1.g = clamp(color1.g.int + Step, 0, 255).uint8
    upd = true
  if ScancodeE.pressed:
    color1.b = clamp(color1.b.int + Step, 0, 255).uint8
    upd = true
  if ScancodeR.pressed:
    color1.a = clamp(color1.a.int + Step, 0, 255).uint8
    upd = true
  if ScancodeA.pressed:
    color1.r = clamp(color1.r.int - Step, 0, 255).uint8
    upd = true
  if ScancodeS.pressed:
    color1.g = clamp(color1.g.int - Step, 0, 255).uint8
    upd = true
  if ScancodeD.pressed:
    color1.b = clamp(color1.b.int - Step, 0, 255).uint8
    upd = true
  if ScancodeF.pressed:
    color1.a = clamp(color1.a.int - Step, 0, 255).uint8
    upd = true

  # color2
  if ScancodeT.pressed:
    color2.r = clamp(color2.r.int + Step, 0, 255).uint8
    upd = true
  if ScancodeY.pressed:
    color2.g = clamp(color2.g.int + Step, 0, 255).uint8
    upd = true
  if ScancodeU.pressed:
    color2.b = clamp(color2.b.int + Step, 0, 255).uint8
    upd = true
  if ScancodeI.pressed:
    color2.a = clamp(color2.a.int + Step, 0, 255).uint8
    upd = true
  if ScancodeG.pressed:
    color2.r = clamp(color2.r.int - Step, 0, 255).uint8
    upd = true
  if ScancodeH.pressed:
    color2.g = clamp(color2.g.int - Step, 0, 255).uint8
    upd = true
  if ScancodeJ.pressed:
    color2.b = clamp(color2.b.int - Step, 0, 255).uint8
    upd = true
  if ScancodeK.pressed:
    color2.a = clamp(color2.a.int - Step, 0, 255).uint8
    upd = true

  if upd:
    scene.idximg.palette[3] = color1
    scene.idximg.palette[11] = color2
    discard scene.knightG.assignTexture(scene.idximg.render())



================================================
FILE: demos/demo19/README.md
================================================
Nimgame 2: Demo 19
==================

PerspectiveImage. Demonstrates perspective transformations.

![Screenshot](demo19.png)



================================================
FILE: demos/demo19/demo19.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 19 (PerspectiveImage)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo19/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/perspectiveimage,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types


const
  GraphicCount = 17
  Positions: array[GraphicCount, Coord] = [
    (125.0, 125.0), (275, 125), (375, 125), (475, 125), (575, 125),
    (75, 275), (175, 275), (275, 275), (375, 275), (475, 275), (575, 275),
    (75, 425), (175, 425), (275, 425), (375, 425), (475, 400), (575, 425),
  ]


type
  MainScene = ref object of Scene
    pimg: PerspectiveImage
    graphics: array[GraphicCount, TextureGraphic]
    entities: array[GraphicCount, Entity]


proc init*(scene: MainScene) =
  Scene(scene).init()

  scene.pimg = newPerspectiveImage("../assets/gfx/grid.png")

  # graphics
  for i in 0..scene.graphics.high:
    scene.graphics[i] = newTextureGraphic()

  discard scene.graphics[0].assignTexture(scene.pimg.render(
    pdHor, 0, 0))
  discard scene.graphics[1].assignTexture(scene.pimg.render(
    pdHor, 96, 32))
  discard scene.graphics[2].assignTexture(scene.pimg.render(
    pdHor, 32, 96))
  discard scene.graphics[3].assignTexture(scene.pimg.render(
    pdHor, 64, 32, 32))
  discard scene.graphics[4].assignTexture(scene.pimg.render(
    pdHor, 32, 64, 32))
  discard scene.graphics[5].assignTexture(scene.pimg.render(
    pdVer, 96, 32))
  discard scene.graphics[6].assignTexture(scene.pimg.render(
    pdVer, 64, 32, 32))
  discard scene.graphics[7].assignTexture(scene.pimg.render(
    pdHor, 64, 32, shift = 0.0))
  discard scene.graphics[8].assignTexture(scene.pimg.render(
    pdHor, 32, 64, shift = 1.0))
  discard scene.graphics[9].assignTexture(scene.pimg.render(
    pdHor, 64, 32, shift = 0.25))
  discard scene.graphics[10].assignTexture(scene.pimg.render(
    pdHor, 32, 64, shift = 0.75))
  discard scene.graphics[11].assignTexture(scene.pimg.render(
    pdVer, 32, 96))
  discard scene.graphics[12].assignTexture(scene.pimg.render(
    pdVer, 32, 64, 32))
  discard scene.graphics[13].assignTexture(scene.pimg.render(
    pdVer, 64, 32, shift = 0.0))
  discard scene.graphics[14].assignTexture(scene.pimg.render(
    pdVer, 64, 32, shift = 1.0))
  discard scene.graphics[15].assignTexture(scene.pimg.render(
    pdVer, 64, 32, shift = 0.25))
  discard scene.graphics[16].assignTexture(scene.pimg.render(
    pdVer, 32, 64, shift = 0.75))

  # entities
  for i in 0..scene.entities.high:
    scene.entities[i] = newEntity()
    scene.entities[i].graphic = scene.graphics[i]
    scene.entities[i].centrify()
    scene.entities[i].pos = Positions[i]

  # add to scene
  for entity in scene.entities:
    scene.add(entity)


proc free*(scene: MainScene) =
  scene.pimg.free()
  for graphic in scene.graphics:
    graphic.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  scene.eventScene(event)
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()



================================================
FILE: demos/demo2/README.md
================================================
Nimgame 2: Demo 2
=================

Graphic demo.

Demonstrates color and alpha modifiers, blending modes, and scaling.

![Screenshot](demo2.png)



================================================
FILE: demos/demo2/demo2.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 2 (Graphic)",
             scaleQuality = 0):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo2/earth.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Earth* = ref object of Entity


proc init*(entity: Earth) =
  entity.initEntity()
  entity.pos.x = 128.0
  entity.pos.y = 96.0


proc newEarth*(): Earth =
  result = new Earth
  result.init()



================================================
FILE: demos/demo2/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  earth, spaceman


type
  MainScene = ref object of Scene
    earthG, spacemanG: TextureGraphic
    e: Earth
    s: Spaceman


proc init*(scene: MainScene) =
  Scene(scene).init()
  # Earth
  scene.e = newEarth()
  scene.earthG = newTextureGraphic()
  discard scene.earthG.load("../assets/gfx/earth.png")
  scene.e.graphic = scene.earthG
  # Spaceman
  scene.s = newSpaceman()
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")
  scene.s.graphic = scene.spacemanG

  # add to scene
  scene.add(scene.s)
  scene.add(scene.e)


proc free*(scene: MainScene) =
  scene.earthG.free
  scene.spacemanG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


proc changeBlendMod(scene: MainScene, increase = true) =
  # get blend mod
  var b = TextureGraphic(scene.s.graphic).blendMod
  # change blend mod
  if increase:
    if b.int == 0:
      b = Blend(1)
    elif b < Blend.high:
      b = Blend(b.int shl 1)
  else: # decrease
    if b.int > 0:
      b = Blend(b.int shr 1)
  # set blend mod
  TextureGraphic(scene.s.graphic).blendMod = b


const
  ScaleMax = 3
  ScaleMin = 0.5
  ScaleMod = 0.25

proc changeResolution(scene: MainScene, increase = true) =
  # get current scale
  var scale = game.scale
  # change scale
  if increase:
    if scale.x < ScaleMax:
      scale.x += ScaleMod
      scale.y += ScaleMod
  else: # decrease
    if scale.x > ScaleMin:
      scale.x -= ScaleMod
      scale.y -= ScaleMod
  # set resolution
  game.windowSize = Dim(Coord(game.size) * scale)


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_T:
      scene.changeBlendMod()
    of K_G:
      scene.changeBlendMod(false)
    of K_Y:
      scene.changeResolution()
    of K_H:
      scene.changeResolution(false)
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  let c = TextureGraphic(scene.s.graphic).colorMod
  let res = game.windowSize
  let scale: Coord = (game.scale.x.round(2), game.scale.y.round(2))
  discard box((4, 60), (220, 124), 0x000000CC'u32)
  discard string(
    (8, 64), "Q/A - red mod: " & $c.r.int, 0xFF0000FF'u32)
  discard string(
    (8, 72), "W/S - green mod: " & $c.g.int, 0xFF0000FF'u32)
  discard string(
    (8, 80), "E/D - blue mod: " & $c.b.int, 0xFF0000FF'u32)
  discard string(
    (8, 88), "R/F - alpha mod: " &
      $TextureGraphic(scene.s.graphic).alphaMod.int, 0xFF0000FF'u32)
  discard string(
    (8, 96), "T/G - blend mod: " &
      $TextureGraphic(scene.s.graphic).blendMod, 0xFF0000FF'u32)
  discard string(
    (8, 104), "Y/H - resolution: " & $res.w & "x" & $res.h, 0xFF0000FF'u32)
  discard string(
    (8, 112), "Scale: " & $scale.x & "x" & $scale.y, 0xFF0000FF'u32)


type
  ColorElement = enum
    ceR, ceG, ceB


proc changeColorMod(scene: MainScene, elem: ColorElement, val: int) =
  var color = TextureGraphic(scene.s.graphic).colorMod
  # Get color element
  var e = int(case elem:
              of ceR: color.r
              of ceG: color.g
              of ceB: color.b)
  # Change color element
  inc(e, val)
  # Correct value
  if e < 0x00: e = 0x00
  elif e > 0xFF: e = 0xFF
  # Set color mod
  case elem:
  of ceR: color.r = e.uint8
  of ceG: color.g = e.uint8
  of ceB: color.b = e.uint8
  TextureGraphic(scene.s.graphic).colorMod = color


proc changeAlphaMod(scene: MainScene, val: int) =
  # Get alpha mod
  var a = TextureGraphic(scene.s.graphic).alphaMod.int
  # Change alpha mod
  inc(a, val)
  # Correct value
  if a < 0x00: a = 0x00
  elif a > 0xFF: a = 0xFF
  # Set alpha mod
  TextureGraphic(scene.s.graphic).alphaMod = a.uint8


method update*(scene: MainScene, elapsed: float) =
  let val = int(0xFF * elapsed)
  scene.updateScene(elapsed)
  if ScancodeQ.down: scene.changeColorMod(ceR, val)
  if ScancodeA.down: scene.changeColorMod(ceR, -val)
  if ScancodeW.down: scene.changeColorMod(ceG, val)
  if ScancodeS.down: scene.changeColorMod(ceG, -val)
  if ScancodeE.down: scene.changeColorMod(ceB, val)
  if ScancodeD.down: scene.changeColorMod(ceB, -val)
  if ScancodeR.down: scene.changeAlphaMod(val)
  if ScancodeF.down: scene.changeAlphaMod(-val)



================================================
FILE: demos/demo2/spaceman.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Spaceman* = ref object of Entity


proc init*(entity: Spaceman) =
  entity.initEntity()
  entity.pos.x = 200.0
  entity.pos.y = 64.0


proc newSpaceman*(): Spaceman =
  result = new Spaceman
  result.init()



================================================
FILE: demos/demo20/README.md
================================================
Nimgame 2: Demo 20
==================

TextureAtlas. Demonstrates texture atlas loading and access.

![Screenshot](demo20.png)



================================================
FILE: demos/demo20/demo20.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 320, h = 240, title = "Nimgame 2: Demo 20 (TextureAtlas)"):
  showInfo = true
  game.windowSize = (640, 480)
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo20/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/gui/button,
  nimgame2/texturegraphic,
  nimgame2/textureatlas,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types


type
  MainScene = ref object of Scene
    atlas: TextureAtlas


proc init*(scene: MainScene) =
  Scene(scene).init()

  scene.atlas = newTextureAtlas("../assets/gfx/atlas.png",
                                "../assets/csv/atlas.csv")

  let
    eSpaceman = newEntity()
    eGradient = newEntity()
    eButton = newGuiButton(scene.atlas["button"])
    eSprite = newEntity()

  eSpaceman.graphic = scene.atlas["spaceman"]
  eSpaceman.pos = (50.0, 100.0)

  eGradient.graphic = scene.atlas["gradient"]
  eGradient.pos = (150.0, 100.0)

  eButton.pos = (200.0, 100.0)

  eSprite.graphic = scene.atlas["sprite"]
  eSprite.initSprite((32, 32), (0, 32), (1, 1))
  discard eSprite.addAnimation("play", toSeq(0..3), 1/4)
  eSprite.play("play")
  eSprite.pos = (200.0, 150.0)

  scene.add(eSpaceman)
  scene.add(eGradient)
  scene.add(eButton)
  scene.add(eSprite)


proc free*(scene: MainScene) =
  scene.atlas.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  scene.eventScene(event)
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()



================================================
FILE: demos/demo21/README.md
================================================
Nimgame 2: Demo 21
==================

Joysticks. Demonstrates joystick input handling.

![Screenshot](demo21.png)



================================================
FILE: demos/demo21/demo21.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 21 (Joysticks)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo21/joypoint.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/textgraphic,
  nimgame2/texturegraphic,
  nimgame2/font,
  nimgame2/bitmapfont,
  nimgame2/input,
  nimgame2/types


type
  JoyPoint* = ref object of Entity
    joy: int
    label: TextGraphic


proc init(jp: JoyPoint, id: int) =
  jp.initEntity()
  jp.joy = id
  jp.graphic = newTextureGraphic("../assets/gfx/target.png")
  jp.centrify()
  jp.pos = game.size / 2
  # label
  let font = newBitmapFont()
  discard font.load("../assets/fnt/default8x16.png", (8, 16))
  jp.label = newTextGraphic(font)
  jp.label.lines = [$id]


proc newJoyPoint*(joystick: int): JoyPoint =
  new result
  result.init(joystick)


method render*(jp: JoyPoint) =
  jp.renderEntity()
  jp.label.draw(
    jp.absPos + jp.center - Coord(jp.label.dim / 2) + (1.0, 1.0),
    jp.absRot,
    jp.absScale,
    jp.center,
    jp.flip)


const Speed = 100

method update*(jp: JoyPoint, elapsed: float) =
  let move = Speed * elapsed / JoyAxis.high.float
  jp.updateEntity(elapsed)
  jp.pos.x += jp.joy.joyAxis(0).float * move
  jp.pos.x = clamp(jp.pos.x, 0.0, game.size.w.float)
  jp.pos.y += jp.joy.joyAxis(1).float * move
  jp.pos.y = clamp(jp.pos.y, 0.0, game.size.h.float)



================================================
FILE: demos/demo21/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  joypoint


type
  MainScene = ref object of Scene
    joypoints: seq[JoyPoint]


proc init*(scene: MainScene) =
  Scene(scene).init()
  scene.joypoints = @[]
  for i in 0..<numJoysticks():
    discard openJoystick(i)
    scene.joypoints.add(newJoyPoint(i))
    scene.add(scene.joypoints[^1])


proc free*(scene: MainScene) =
  discard

proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  scene.eventScene(event)
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


proc joyInfo(id: int): string =
  result = joyName(id)
  for i in 0..<joyNumButtons(id):
    if joyDown(id, i):
      result &= " " & $i


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (260, 84), 0x000000CC'u32)
  var y = 64
  for i in 0..<numJoysticks():
    discard string(
      (8, y), joyInfo(i), 0xFFFFFFFF'u32)
    y += 8


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)



================================================
FILE: demos/demo22/README.md
================================================
Nimgame 2: Demo 22
==================

MpegGraphic demo.

![Screenshot](demo22.png)



================================================
FILE: demos/demo22/demo22.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 22 (MpegGraphic)",
             scaleQuality = 0):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo22/mainscene.nim
================================================
import
  strutils,
  nimgame2/plugin/mpeggraphic,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  nimgame2/utils


type
  MainScene = ref object of Scene
    movie: MpegGraphic
    e: Entity


proc moviePhysics*(entity: Entity, elapsed: float) =
  defaultPhysics(entity, elapsed)

  # Screen collision
  if entity.pos.x < 0:
    entity.vel.x *= -1
  if entity.pos.y < 0:
    entity.vel.y *= -1
  if entity.pos.x >= game.size.w.float:
    entity.vel.x *= -1
  if entity.pos.y >= game.size.h.float:
    entity.vel.y *= -1


proc init*(scene: MainScene) =
  Scene(scene).init()
  # Movie
  scene.movie = newMpegGraphic("video.mpg")
  scene.movie.loop = true
  scene.e = newEntity()
  scene.e.graphic = scene.movie
  scene.e.physics = moviePhysics
  scene.e.pos.x = rand(game.size.w).float
  scene.e.pos.y = rand(game.size.h).float
  scene.e.vel.x = rand(10.0..100.0) * randSign().float
  scene.e.vel.y = rand(10.0..100.0) * randSign().float
  scene.e.centrify()
  scene.e.rotVel = rand(10.0..60.0) * randSign().float

  # add to scene
  scene.add(scene.e)


proc free*(scene: MainScene) =
  scene.movie.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (220, 124), 0x000000CC'u32)
  discard string(
    (8, 64), "Enter - play", 0xFF0000FF'u32)
  discard string(
    (8, 72), "Space - pause", 0xFF0000FF'u32)
  discard string(
    (8, 80), "Backspace - stop", 0xFF0000FF'u32)
  discard string(
    (8, 88), "R - Rewind", 0xFF0000FF'u32)
  discard string(
    (8, 96), "Up/Down - volume: " & $scene.movie.volume, 0xFF0000FF'u32)
  discard string(
    (8, 104), "Right - skip 5s", 0xFF0000FF'u32)
  discard string(
    (8, 112), "Time: " & scene.movie.currentTime.formatFloat(precision = 3) &
    "s of " & scene.movie.totalTime.formatFloat(precision = 3) & "s", 0xFF0000FF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if ScancodeReturn.pressed: scene.movie.play()
  if ScancodeSpace.pressed: scene.movie.pause()
  if ScancodeBackspace.pressed: scene.movie.stop()
  if ScancodeR.pressed: scene.movie.rewind()
  if ScancodeUp.pressed: scene.movie.volume =
    (scene.movie.volume + 10).clamp(0, 100)
  if ScancodeDown.pressed: scene.movie.volume =
    (scene.movie.volume - 10).clamp(0, 100)
  if ScancodeRight.pressed: scene.movie.skip(5.0)



================================================
FILE: demos/demo23/README.md
================================================
Nimgame 2: Demo 23
==================

Transform demo by [CodeDoes](https://github.com/CodeDoes).

![Screenshot](demo23.png)



================================================
FILE: demos/demo23/demo23.nim
================================================
import
  nimgame2 / [
    nimgame, settings
  ],
  mainscene


game = newGame()
if game.init(640, 480, "Nimgame 2: Demo 22 (Transform)"):
  game.scene = newMainScene()
  settings.updateInterval = 1000
  settings.showInfo = true
  game.run()



================================================
FILE: demos/demo23/mainscene.nim
================================================
import
  nimgame2 / [
    truetypefont, textgraphic, entity,
    nimgame, scene, types,
    graphic, input, settings],
  nimgame2 / gui / widget,
  private / [
    circle_graphic,
    frame]


type
  MainScene* = ref object of Scene
    font*: TrueTypeFont


proc newCircleEntity*(): Entity =
  var cgraphic = newCircleGraphic()
  cgraphic.radius = 4.0
  cgraphic.draw_border = false

  result = newEntity()
  result.graphic = cgraphic
  result.centrify()


proc createRotScaleTestEnts*(
    scene: MainScene, text: string,
    pos: var Coord, rot: Angle = 0.0, scale: Scale = 1.0) =
  var
    textEnt = newEntity()
    textgraphic = newTextGraphic(scene.font)

  scene.add(textEnt)
  textEnt.graphic = textgraphic

  textgraphic.setText text

  textEnt.scale = scale
  textEnt.pos = pos + (textEnt.bottomleft * textEnt.absScale)
  textEnt.center += textEnt.bottomleft
  echo textEnt.pos
  # Want rel_pos before rotation
  pos.y = (textEnt.transform * textEnt.bottomleft).y
  textEnt.rot = rot * 90.0
  for p in textEnt.world_corners.items():
    var cent = newCircleEntity()
    scene.add(cent)
    cent.pos = p
  var frameEnt = newGuiWidget()
  scene.add(frameEnt)
  var fGraphic = newFrameGraphic()
  frameEnt.graphic = fGraphic
  fGraphic.draw_filled = false
  fGraphic.border_color = ColorRed
  fGraphic.rect.x = textEnt.topleft.x.cint
  fGraphic.rect.y = textEnt.topleft.y.cint
  fGraphic.rect.w = textEnt.dim.w.cint
  fGraphic.rect.h = textEnt.dim.h.cint
  frameEnt.logic = proc (entity: Entity, elapsed: float) =
    let color =
      if entity.GuiWidget.state.isFocused: ColorOrange
      else: ColorGreen
    entity.graphic.FrameGraphic.border_color = color

  frameEnt.center = textEnt.center
  frameEnt.pos = textEnt.pos
  frameEnt.rot = textEnt.rot
  frameEnt.scale = textEnt.scale
  var corners = newseq[Coord]()
  for c in frameEnt.corners:
    corners.add(c)
  frameEnt.collider = frameEnt.newPolyCollider(frameEnt.pos, corners)


proc init*(scene: MainScene) =
  scene.Scene.init()
  scene.font = newTrueTypeFont()
  discard scene.font.load("../assets/fnt/FSEX300.ttf", 32)

  var rel_pos: Coord = (0.0, 100.0)
  for scale in [0.8, 0.3, 0.4, 0.6, 0.7, 0.2]:
    createRotScaleTestEnts(scene, "Scale Test", rel_pos, scale = scale)

  for f in [0.8, 0.3, 0.4, 0.6, 0.7, 0.2]:
    createRotScaleTestEnts(scene, "Rot Scale Test", rel_pos, rot = f, scale = f)

  rel_pos = (400.0, 0.0)
  for rot in [0.8, 0.3, 0.4, 0.6, 0.7, 0.2]:
    createRotScaleTestEnts(scene, "Rot Test", rel_pos, rot = rot)


proc newMainScene*(): MainScene =
  new result
  result.init()



================================================
FILE: demos/demo23/private/border_fill_graphic.nim
================================================
import
  nimgame2 / [
    types, graphic, types
  ]


type
  BorderFillGraphic* = ref object of Graphic
    border_color*, fill_color*: Color
    # border_thickness*: float #NOTE can't set border thickness at the moment
    draw_border*, draw_filled*: bool


proc initBorderFillGraphic*(self: BorderFillGraphic) =
  self.draw_border = true
  self.draw_filled = true
  self.fill_color = ColorPurple ## Traditional visual debugging color
  self.border_color = ColorPink
  # self.border_thickness = 1.0


method draw*(graphic: BorderFillGraphic,
             pos: Coord = (0.0, 0.0),
             angle: Angle = 0.0,
             scale: Scale = 1.0,
             center: Coord = (0.0, 0.0),
             flip: Flip = Flip.none,
             region: Rect = Rect(x: 0, y: 0, w: 0, h: 0)) =
  raise newException(CatchableError, "Can't use BorderFillGraphic draw method.")


method dim*(graphic: BorderFillGraphic): Dim =
  raise newException(CatchableError, "Can't use BorderFillGraphic dim method.")



================================================
FILE: demos/demo23/private/circle_graphic.nim
================================================
import
  nimgame2 / [
    types, graphic, draw, utils
  ],
  border_fill_graphic


type
  CircleGraphic* = ref object of BorderFillGraphic
    radius*: float


proc drawCircleGraphic*(self: CircleGraphic,
                        pos: Coord = (0.0, 0.0),
                        angle: Angle = 0.0,
                        scale: Scale = 1.0,
                        center: Coord = (0.0, 0.0),
                        flip: Flip = Flip.none,
                        region: Rect = Rect(x: 0, y: 0, w: 0, h: 0)) =
  let point: Coord = pos
  if self.draw_filled:
    discard circle(point, self.radius, self.fill_color, DrawMode.filled)
  if self.draw_border:
    discard circle(point, self.radius, self.border_color, DrawMode.default)


method draw*(graphic: CircleGraphic,
             pos: Coord = (0.0, 0.0),
             angle: Angle = 0.0,
             scale: Scale = 1.0,
             center: Coord = (0.0, 0.0),
             flip: Flip = Flip.none,
             region: Rect = Rect(x: 0, y: 0, w: 0, h: 0)) =
  drawCircleGraphic(graphic, pos, angle, scale, center, flip, region)


proc newCircleGraphic*(): CircleGraphic =
  new result
  result.initBorderFillGraphic()
  result.radius = 5.0


method dim*(self: CircleGraphic): Dim =
  return (int self.radius * 2, int self.radius * 2)


================================================
FILE: demos/demo23/private/frame.nim
================================================
import 
  nimgame2 / [
    types, graphic, draw, utils
  ],
  border_fill_graphic

type
  FrameGraphic* = ref object of BorderFillGraphic
    rect*: Rect

  Bounds = tuple[a: Coord, b: Coord]

  AngledBounds* = ref object of RootObj
    bounds*: Bounds
    angle*: Angle
    center*: Coord


proc points*(abounds: AngledBounds): auto {.inline.} =
  let
    a = abounds.bounds.a
    b = abounds.bounds.b
    center = abounds.center
    angle = abounds.angle

  template apply(coord: Coord): Coord =
    rotate(coord, center, angle)

  return @[
    apply(a),
    apply((b.x, a.y)),
    apply(b),
    apply((a.x, b.y))
  ]


proc points*(graphic: FrameGraphic, pos: Coord, angle: Angle,
             scale: Scale, center: Coord): seq[Coord] =
  var
    abounds = new AngledBounds

  abounds.bounds = (a: -center * scale,
                    b: (-center + graphic.dim.toCoord) * scale).Bounds
  abounds.angle = angle
  abounds.center = pos
  return abounds.points


proc initFrameGraphic(graphic: FrameGraphic) =
  graphic.initBorderFillGraphic()
  graphic.rect= Rect(x: 0, y: 0, w: 0, h: 0)


proc newFrameGraphic*(): FrameGraphic =
  new result
  result.initFrameGraphic()


method dim*(self: FrameGraphic): Dim =
  (self.rect.w.int, self.rect.h.int)


proc drawFrameGraphic*(self: FrameGraphic,
                       pos: Coord,
                       angle: Angle,
                       scale: Scale,
                       center: Coord,
                       flip: Flip,
                       region: Rect) =
  var points = self.points(pos,angle, scale,center)
  if self.draw_border:
    discard draw.polygon(points, self.border_color, DrawMode.default)
  if self.draw_filled:
    discard draw.polygon(points, self.fill_color, DrawMode.filled)


method draw*(
    graphic: FrameGraphic,
    pos: Coord = (0.0, 0.0),
    angle: Angle = 0.0,
    scale: Scale = 1.0,
    center: Coord = (0.0, 0.0),
    flip: Flip = Flip.none,
    region: Rect = Rect(x: 0, y: 0, w: 0, h: 0)) =
  drawFrameGraphic(graphic, pos, angle, scale, center, flip, region)



================================================
FILE: demos/demo3/README.md
================================================
Nimgame 2: Demo 3
=================

Input demo. Demonstrates keyboard and mouse input.

![Screenshot](demo3.png)



================================================
FILE: demos/demo3/demo3.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 3 (Input & Physics)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo3/mainscene.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  spaceman


type
  MainScene = ref object of Scene
    spacemanG: TextureGraphic
    s: Spaceman


proc spacemanPhysics(entity: Entity, elapsed: float) =
  defaultPhysics(entity, elapsed)
  if entity.pos.x.int < 0:
    entity.pos.x = 0
    entity.vel.x = 0
  if entity.pos.x.int > game.size.w:
    entity.pos.x = game.size.w.float
    entity.vel.x = 0
  if entity.pos.y.int < 0:
    entity.pos.y = 0
    entity.vel.y = 0
  if entity.pos.y.int > game.size.h:
    entity.pos.y = game.size.h.float
    entity.vel.y = 0


proc init*(scene: MainScene) =
  Scene(scene).init()
  # Spaceman
  scene.s = newSpaceman()
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")
  scene.s.graphic = scene.spacemanG
  scene.s.physics = spacemanPhysics
  scene.s.centrify()
  scene.add(scene.s)
  # Mouse
  #discard mouseRelative(true)

proc free*(scene: MainScene) =
  scene.spacemanG.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  # Draw line between the spaceman and the mouse position if LMB is pressed
  if MouseButton.left.down:
    discard line(scene.s.pos, mouse.abs, 0xFF0000FF'u32)

  scene.renderScene()

  var arrows: string = ""
  if ScancodeUp.down: arrows &= "Up "
  if ScancodeDown.down: arrows &= "Down "
  if ScancodeLeft.down: arrows &= "Left "
  if ScancodeRight.down: arrows &= "Right"

  var wsad: string = ""
  if ScancodeW.down: wsad &= "W "
  if ScancodeS.down: wsad &= "S "
  if ScancodeA.down: wsad &= "A "
  if ScancodeD.down: wsad &= "D "

  var mouse: string = "Abs(" & $mouse.abs.x.int & ":" & $mouse.abs.y.int &
                      ") Rel(" & $mouse.rel.x.int & ":" & $mouse.rel.y.int & ")"

  var buttons: string = ""
  if MouseButton.left.down: buttons &= "L "
  if MouseButton.middle.down: buttons &= "M "
  if MouseButton.right.down: buttons &= "R "
  if MouseButton.x1.down: buttons &= "X1 "
  if MouseButton.x2.down: buttons &= "X2 "


  discard box((4, 60), (260, 100), 0xCC000000'u32)
  discard string(
    (8, 64), "Arrows: " & arrows, 0xFF0000FF'u32)
  discard string(
    (8, 72), "WSAD: " & wsad, 0xFF0000FF'u32)
  discard string(
    (8, 80), "Mouse: " & mouse, 0xFF0000FF'u32)
  discard string(
    (8, 88), "Mouse buttons: " & buttons, 0xFF0000FF'u32)
  discard string(
    (8, 96), "Mouse wheel: " & $mouseWheel, 0xFF0000FF'u32)

const
  Acc = 100.0


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  # Arrows and WSAD
  if ScancodeUp.down or ScancodeW.down: scene.s.vel.y -= Acc * elapsed
  if ScancodeDown.down or ScancodeS.down: scene.s.vel.y += Acc * elapsed
  if ScancodeLeft.down or ScancodeA.down: scene.s.vel.x -= Acc * elapsed
  if ScancodeRight.down or ScancodeD.down: scene.s.vel.x += Acc * elapsed
  # Mouse
  if MouseButton.left.down:
    var vector: Coord
    vector = (mouse.abs - scene.s.pos) * elapsed
    scene.s.vel += vector



================================================
FILE: demos/demo3/spaceman.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Spaceman* = ref object of Entity


proc init*(entity: Spaceman) =
  entity.initEntity()
  entity.pos.x = game.size.w.float / 2
  entity.pos.y = game.size.h.float / 2
  entity.drg.x = 10.0
  entity.drg.y = 10.0


proc newSpaceman*(): Spaceman =
  result = new Spaceman
  result.init()



================================================
FILE: demos/demo4/README.md
================================================
Nimgame 2: Demo 4
=================

Sprite demo. Demonstrates sprite animation.

![Screenshot](demo4.png)



================================================
FILE: demos/demo4/demo4.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 4 (Sprite & Animation)"):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo4/dwarf.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Dwarf* = ref object of Entity


proc init*(entity: Dwarf) =
  entity.initEntity()
  entity.centrify()
  entity.physics = defaultPhysics


proc newDwarf*(): Dwarf =
  result = new Dwarf
  result.init()



================================================
FILE: demos/demo4/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  dwarf


type
  MainScene = ref object of Scene
    dG: TextureGraphic
    d: Dwarf


const Framerate = 1/12


proc init*(scene: MainScene) =
  Scene(scene).init()
  # Dwarf
  scene.dG = newTextureGraphic()
  discard scene.dG.load("../assets/gfx/dwarf.png")
  scene.d = newDwarf()
  scene.d.pos = (200, 100)
  scene.d.graphic = scene.dG
  scene.d.initSprite((24, 48))
  discard scene.d.addAnimation(
    "down", [0, 1, 2, 3, 4, 5], Framerate)
  discard scene.d.addAnimation(
    "up", [6, 7, 8, 9, 10, 11], Framerate)
  discard scene.d.addAnimation(
    "left", [12, 13, 14, 15, 16, 17], Framerate)
  discard scene.d.addAnimation(
    "right", [12, 13, 14, 15, 16, 17], Framerate, Flip.horizontal)
  scene.add(scene.d)


proc free*(scene: MainScene) =
  scene.dG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
      case event.key.keysym.sym:
      of K_Escape:
        gameRunning = false
      else: discard


method render*(scene: MainScene) =
  scene.renderScene()


const Speed = 50


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)

  # Controls and speed
  type Direction = enum none, down, up, left, right
  var direction =
    if ScancodeDown.down or ScancodeS.down: down
    elif ScancodeUp.down or ScancodeW.down: up
    elif ScancodeLeft.down or ScancodeA.down: left
    elif ScancodeRight.down or ScancodeD.down: right
    else: none

  case direction:
  of none:
    if not scene.d.sprite.playing:
      scene.d.vel = (0, 0)
  of down:
    if  not scene.d.sprite.playing or
        (scene.d.currentAnimationName != "down"):
      scene.d.play("down", 1)
      scene.d.vel = (0, Speed)
  of up:
    if  not scene.d.sprite.playing or
        (scene.d.currentAnimationName != "up"):
      scene.d.play("up", 1)
      scene.d.vel = (0, -Speed)
  of left:
    if  not scene.d.sprite.playing or
        (scene.d.currentAnimationName != "left"):
      scene.d.play("left", 1)
      scene.d.vel = (-Speed, 0)
  of right:
    if  not scene.d.sprite.playing or
        (scene.d.currentAnimationName != "right"):
      scene.d.play("right", 1)
      scene.d.vel = (Speed, 0)



================================================
FILE: demos/demo5/README.md
================================================
Nimgame 2: Demo 5
=================

Colliders demo. Demonstrates different colliders.

![Screenshot](demo5.png)



================================================
FILE: demos/demo5/cursor.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity,
  nimgame2/input

type
  Cursor* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Cursor) =
  entity.initEntity()
  entity.tags.add("Cursor")
  entity.pos = mouse.abs
  entity.collidedWith = @[]


proc newCursor*(): Cursor =
  result = new Cursor
  result.init()


method update*(entity: Cursor, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]
  entity.pos = mouse.abs


method onCollide*(entity: Cursor, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/demo5.nim
================================================
import
  sdl2_nim/sdl,
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 5 (Collisions)",
             scaleQuality = 0):
  showInfo = true
  colliderOutline = true
  discard sdl.showCursor(0)
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo5/earth.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Earth* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Earth) =
  entity.initEntity()
  entity.tags.add("Earth")
  entity.pos = (0.0, 150.0)
  entity.collidedWith = @[]


proc newEarth*(): Earth =
  result = new Earth
  result.init()


method update*(entity: Earth, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Earth, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/line.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Line* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Line) =
  entity.initEntity()
  entity.tags.add("Line")
  entity.collidedWith = @[]


proc newLine*(): Line =
  result = new Line
  result.init()


method update*(entity: Line, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Line, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  cursor, earth, line, poly1, poly2, poly3, poly9, spaceman


type
  MainScene = ref object of Scene
    cursorG, earthG, spacemanG: TextureGraphic
    c: Cursor
    e: Earth
    d1, d2: Line
    s: Spaceman
    p1: Poly1
    p2: Poly2
    p3: Poly3
    p9: Poly9


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Cursor
  scene.c = newCursor()
  scene.cursorG = newTextureGraphic()
  discard scene.cursorG.load("../assets/gfx/cursor.png")
  scene.c.graphic = scene.cursorG
  scene.c.collider = newCollider(scene.c)

  # Line 1
  scene.d1 = newLine()
  scene.d1.pos = (50.0, 420.0)
  scene.d1.center = (25.0, 0.0)
  scene.d1.collider = scene.d1.newLineCollider((-25, 0), (25, 0))

  # Line 2
  scene.d2 = newLine()
  scene.d2.pos = (50.0, 450.0)
  scene.d2.collider = scene.d2.newLineCollider((0, 0), (100, 0))

  # Earth
  scene.e = newEarth()
  scene.earthG = newTextureGraphic()
  discard scene.earthG.load("../assets/gfx/earth.png")
  scene.e.graphic = scene.earthG
  let radius = scene.earthG.dim.w.float / 2
  scene.e.collider = newCircleCollider(scene.e, (radius, radius), radius)

  # Spaceman
  scene.s = newSpaceman()
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")
  scene.s.graphic = scene.spacemanG
  scene.s.centrify()
  scene.s.collider = newBoxCollider(scene.s, (0, 0), scene.spacemanG.dim)

  # Poly1
  scene.p1 = newPoly1()
  scene.p1.pos = (350, 160)

  # Poly2
  scene.p2 = newPoly2()
  scene.p2.pos = (350, 210)

  # Poly3
  scene.p3 = newPoly3()
  scene.p3.pos = (350, 260)

  # Poly9
  scene.p9 = newPoly9()
  scene.p9.pos = (350, 360)

  # add to scene
  scene.add(scene.d1)
  scene.add(scene.d2)
  scene.add(scene.s)
  scene.add(scene.e)
  scene.add(scene.c)
  scene.add(scene.p1)
  scene.add(scene.p2)
  scene.add(scene.p3)
  scene.add(scene.p9)


proc free*(scene: MainScene) =
  scene.earthG.free
  scene.spacemanG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      colliderOutline = not colliderOutline
    else: discard


proc generateCollisionString(name: string, list: seq[string]): string =
  if list.len > 0:
    result = name & " collides with: "
    for tag in list:
      result.add(tag & ", ")
    result = result[0 .. ^3]
  else:
    result = name & " isn't colliding with anything"


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (380, 140), 0x000000CC'u32)

  discard string(
    (8, 64), generateCollisionString("Cursor", scene.c.collidedWith),
    0xFFFFFFFF'u32)

  discard string(
    (8, 72), generateCollisionString("Line", scene.d1.collidedWith),
    0xFFFFFFFF'u32)

  discard string(
    (8, 80), generateCollisionString("Earth", scene.e.collidedWith),
    0xFFFFFFFF'u32)

  discard string(
    (8, 88), generateCollisionString("Spaceman", scene.s.collidedWith),
    0xFFFFFFFF'u32)

  discard string(
    (8, 96), generateCollisionString("Poly9", scene.p9.collidedWith),
    0xFFFFFFFF'u32)

  discard string(
    (8, 120), "Space toggles outlines, Arrows control spaceman",
    0xFFFFFFFF'u32)

  discard string(
    (8, 128), "WASDQE control line, IJKLUO control polygon",
    0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  # Spaceman
  if ScancodeRight.down: scene.s.pos.x += 1
  if ScancodeLeft.down: scene.s.pos.x -= 1
  if ScancodeDown.down: scene.s.pos.y += 1
  if ScancodeUp.down: scene.s.pos.y -= 1
  # Line
  if ScancodeD.down: scene.d1.pos.x += 1
  if ScancodeA.down: scene.d1.pos.x -= 1
  if ScancodeS.down: scene.d1.pos.y += 1
  if ScancodeW.down: scene.d1.pos.y -= 1
  if ScancodeQ.down: scene.d1.rot -= 1
  if ScancodeE.down: scene.d1.rot += 1
  # Poly9
  if ScancodeL.down: scene.p9.pos.x += 1
  if ScancodeJ.down: scene.p9.pos.x -= 1
  if ScancodeK.down: scene.p9.pos.y += 1
  if ScancodeI.down: scene.p9.pos.y -= 1
  if ScancodeU.down: scene.p9.rot -= 1
  if ScancodeO.down: scene.p9.rot += 1



================================================
FILE: demos/demo5/poly1.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Poly1* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Poly1) =
  entity.initEntity()
  entity.tags.add("Poly1")
  entity.collider = entity.newPolyCollider((0.0, 0.0),
    [ (0.0,   0.0)])
  entity.collidedWith = @[]


proc newPoly1*(): Poly1 =
  result = new Poly1
  result.init()


method update*(entity: Poly1, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Poly1, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/poly2.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Poly2* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Poly2) =
  entity.initEntity()
  entity.tags.add("Poly2")
  entity.collider = entity.newPolyCollider((0.0, 0.0),
    [ (0.0,   0.0),
      (50.0,  0.0)])
  entity.collidedWith = @[]


proc newPoly2*(): Poly2 =
  result = new Poly2
  result.init()


method update*(entity: Poly2, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Poly2, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/poly3.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Poly3* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Poly3) =
  entity.initEntity()
  entity.tags.add("Poly3")
  entity.collider = entity.newPolyCollider((0.0, 0.0),
    [ (0.0,   0.0),
      (50.0,  0.0),
      (25.0,  35.0)])
  entity.collidedWith = @[]


proc newPoly3*(): Poly3 =
  result = new Poly3
  result.init()


method update*(entity: Poly3, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Poly3, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/poly9.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Poly9* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Poly9) =
  entity.initEntity()
  entity.tags.add("Poly9")
  entity.centrify
  entity.collider = entity.newPolyCollider((0.0, 0.0),
    [ (-40.0, -50.0),
      (-20.0, -50.0),
      (-30.0,  20.0),
      ( 30.0,  20.0),
      ( 20.0, -50.0),
      ( 40.0, -50.0),
      ( 40.0,  30.0),
      (  0.0,  50.0),
      (-40.0,  30.0)])
  entity.collidedWith = @[]


proc newPoly9*(): Poly9 =
  result = new Poly9
  result.init()


method update*(entity: Poly9, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Poly9, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo5/spaceman.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Spaceman* = ref object of Entity
    collidedWith*: seq[string]


proc init*(entity: Spaceman) =
  entity.initEntity()
  entity.tags.add("Spaceman")
  entity.pos = (450.0, 100.0)
  entity.collidedWith = @[]


proc newSpaceman*(): Spaceman =
  result = new Spaceman
  result.init()


method update*(entity: Spaceman, elapsed: float) =
  entity.updateEntity(elapsed)
  entity.collidedWith = @[]


method onCollide*(entity: Spaceman, target: Entity) =
  if target.tags.len > 0:
    entity.collidedWith.add(target.tags[0])



================================================
FILE: demos/demo6/README.md
================================================
Nimgame 2: Demo 6
=================

Grouping demo. Demonstrates effects of setting up entity parent.

![Screenshot](demo6.png)



================================================
FILE: demos/demo6/demo6.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 6 (Grouping)",
             scaleQuality = 0):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo6/earth.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Earth* = ref object of Entity


proc init*(entity: Earth) =
  entity.initEntity()
  entity.tags.add("Earth")
  entity.pos = (320.0, 240.0)


proc newEarth*(): Earth =
  result = new Earth
  result.init()



================================================
FILE: demos/demo6/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/texturegraphic,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  earth, spaceman


type
  MainScene = ref object of Scene
    cursorG, earthG, spacemanG: TextureGraphic
    e: Earth
    s: Spaceman


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Earth
  scene.e = newEarth()
  scene.earthG = newTextureGraphic()
  discard scene.earthG.load("../assets/gfx/earth.png")
  scene.e.graphic = scene.earthG
  scene.e.centrify()
  scene.e.collider = scene.e.newCircleCollider((0, 0), 128)

  # Spaceman
  scene.s = newSpaceman()
  scene.spacemanG = newTextureGraphic()
  discard scene.spacemanG.load("../assets/gfx/spaceman.png")
  scene.s.graphic = scene.spacemanG
  scene.s.centrify()
  scene.s.parent = scene.e
  scene.s.collider = scene.s.newBoxCollider((0, 0), (100, 160))

  # add to scene
  scene.add(scene.s)
  scene.add(scene.e)


proc free*(scene: MainScene) =
  scene.earthG.free
  scene.spacemanG.free


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      colliderOutline = not colliderOutline
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()
  discard box((4, 60), (260, 100), 0x000000CC'u32)

  discard string((8, 64), "WASD  - move group", 0xFFFFFFFF'u32)
  discard string((8, 72), "QE    - rotate group", 0xFFFFFFFF'u32)
  discard string((8, 80), "RF    - scale group", 0xFFFFFFFF'u32)
  discard string((8, 88), "Space - toggle outlines", 0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if ScancodeD.down: scene.e.pos.x += 1
  if ScancodeA.down: scene.e.pos.x -= 1
  if ScancodeS.down: scene.e.pos.y += 1
  if ScancodeW.down: scene.e.pos.y -= 1
  if ScancodeQ.down: scene.e.rot -= 1
  if ScancodeE.down: scene.e.rot += 1
  if ScancodeR.down: scene.e.scale -= 0.01
  if ScancodeF.down: scene.e.scale += 0.01



================================================
FILE: demos/demo6/spaceman.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Spaceman* = ref object of Entity


proc init*(entity: Spaceman) =
  entity.initEntity()
  entity.tags.add("Spaceman")
  entity.pos = (200.0, 0.0)


proc newSpaceman*(): Spaceman =
  result = new Spaceman
  result.init()


method update*(entity: Spaceman, elapsed: float) =
  entity.updateEntity(elapsed)



================================================
FILE: demos/demo7/README.md
================================================
Nimgame 2: Demo 7
=================

Text demo. Demonstrates bitmap and TrueType fonts.

![Screenshot](demo7.png)



================================================
FILE: demos/demo7/demo7.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 6 (Text)",
             scaleQuality = 0):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo7/earth.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/entity

type
  Earth* = ref object of Entity


proc init*(entity: Earth) =
  entity.initEntity()
  entity.tags.add("Earth")
  entity.pos = (0.0, 50.0)


proc newEarth*(): Earth =
  result = new Earth
  result.init()



================================================
FILE: demos/demo7/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/font,
  nimgame2/bitmapfont,
  nimgame2/truetypefont,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/graphic,
  nimgame2/textgraphic,
  nimgame2/texturegraphic,
  nimgame2/typewriter,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  earth


type
  MainScene = ref object of Scene
    earthG: TextureGraphic
    e: Earth
    bmFont: BitmapFont
    bmText: TextGraphic
    bmEntity: Entity
    ttFont: TrueTypeFont
    ttText: TextGraphic
    ttEntity: Entity
    twText: TextGraphic
    twEntity: Typewriter


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Earth
  scene.e = newEarth()
  scene.earthG = newTextureGraphic()
  discard scene.earthG.load("../assets/gfx/earth.png")
  scene.e.graphic = scene.earthG

  # BitmapFont
  scene.bmFont = newBitmapFont()
  discard scene.bmFont.load("../assets/fnt/default8x16.png", (8, 16))

  # TrueTypeFont
  scene.ttFont = newTrueTypeFont()
  discard scene.ttFont.load("../assets/fnt/FSEX300.ttf", 16)

  # Text
  scene.bmText = newTextGraphic()
  scene.bmText.font = scene.bmFont
  scene.bmText.lines =
    [ "The quick brown fox",
      "jumps over the lazy dog"]

  scene.ttText = newTextGraphic()
  scene.ttText.font = scene.ttFont
  scene.ttText.lines =
    [ "В чащах юга жил бы цитрус?",
      "Да, но фальшивый экземпляр!"]

  scene.twText = newTextGraphic()
  scene.twText.font = scene.ttFont

  # Entity
  scene.bmEntity = newEntity()
  scene.bmEntity.pos = (8, 128)
  scene.bmEntity.graphic = scene.bmText

  scene.ttEntity = newEntity()
  scene.ttEntity.pos = (8, 192)
  scene.ttEntity.graphic = scene.ttText

  scene.twEntity = newTypewriter(scene.twText, 0.1)
  #scene.twEntity.width = 10 # uncomment to enable text wrapping
  scene.twEntity.pos = (300, 8)
  scene.twEntity.add "Fancy typewriter effect!"

  # add to scene
  scene.add(scene.bmEntity)
  scene.add(scene.ttEntity)
  scene.add(scene.twEntity)
  scene.add(scene.e)


proc free*(scene: MainScene) =
  scene.bmFont.free()
  scene.ttFont.free()
  scene.bmText.free()
  scene.ttText.free()


proc newMainScene*(): MainScene =
  new result, free
  result.init()


proc changeAlign(scene: MainScene, increase = true) =
  # get
  var a = scene.bmText.align
  # change
  if increase:
    if a.int == 0:
      a = TextAlign(1)
    elif a < TextAlign.high:
      a = TextAlign(a.int shl 1)
  else: # decrease
    if a.int > 0:
      a = TextAlign(a.int shr 1)
  # set
  scene.bmText.align = a
  scene.ttText.align = a

let
  colors = [0xFFFFFFFF'u32, 0xFF0000FF'u32, 0x00FF00FF'u32, 0x0000FFFF'u32]
  colorNames = ["white", "red", "green", "blue"]
var clr = 0

proc changeColor(scene: MainScene, increase = true) =
  # get alpha
  let a = scene.bmText.color.a
  # change
  if increase:
    if clr < colors.high:
      inc clr
  else: # decrease
    if clr > 0:
      dec clr
  # set
  var color: Color = colors[clr]
  color.a = a
  scene.bmText.color = color
  scene.ttText.color = color


proc changeAlpha(scene: MainScene, increase = true) =
  # get
  var
    c = scene.bmText.color
    a = c.a.int
  # change
  if increase:
    a += 15
  else: # decrease
    a -= 15
  # check limits
  if a < 0:
    a = 0
  if a > 255:
    a = 255
  # set
  c.a = a.uint8
  scene.bmText.color = c
  scene.ttText.color = c


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Q:
      scene.changeAlign()
    of K_A:
      scene.changeAlign(false)
    of K_W:
      scene.changeColor()
    of K_S:
      scene.changeColor(false)
    of K_E:
      scene.changeAlpha()
    of K_D:
      scene.changeAlpha(false)
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()

  discard box((4, 60), (260, 100), 0x000000CC'u32)

  discard string((8, 64), "BitmapFont and TrueTypeFont:", 0xFFFFFFFF'u32)
  discard string((8, 72),
    "QA - change alignment: " & $scene.bmText.align, 0xFFFFFFFF'u32)
  discard string((8, 80),
    "WS - change color: " & colorNames[clr], 0xFFFFFFFF'u32)
  discard string((8, 88),
    "ED - change alpha: " & $scene.bmText.color.a.int, 0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)

  if ScancodeReturn.down: scene.twEntity.force()



================================================
FILE: demos/demo8/README.md
================================================
Nimgame 2: Demo 8
=================

ProcGraphic demo. Demonstrates procedural graphics.

![Screenshot](demo8.png)



================================================
FILE: demos/demo8/demo8.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 8 (ProcGraphic)",
             scaleQuality = 0):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo8/mainscene.nim
================================================
import
  math,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/entity,
  nimgame2/graphic,
  nimgame2/input,
  nimgame2/procgraphic,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  nimgame2/utils


type
  MainScene = ref object of Scene
    polyG: ProcGraphic
    poly: Entity


const polyLines0 = [
  (  0.0, -70.0),
  ( 40.0, -30.0),
  ( 80.0, -50.0),
  ( 60.0,  30.0),
  (-60.0,  30.0),
  (-80.0, -50.0),
  (-40.0, -30.0)]

const polyLines1 = [
  ((-30.0,  10.0), (-30.0, -10.0)),
  ((-30.0, -10.0), (-10.0,  10.0)),
  ((-10.0,  10.0), (-10.0, -10.0)),
  ((  0.0, -10.0), (  0.0,  10.0)),
  (( 10.0,  10.0), ( 10.0, -10.0)),
  (( 10.0, -10.0), ( 20.0,   0.0)),
  (( 20.0,   0.0), ( 30.0, -10.0)),
  (( 30.0, -10.0), ( 30.0,  10.0))]


proc polyProc(graphic: ProcGraphic,
              pos: Coord,
              angle: Angle,
              scale: Scale,
              center: Coord,
              flip: Flip,
              region: Rect) =
  let
    color0: Color = 0xFFFF00FF'u32
    color1: Color = 0x000000FF'u32

  var poly: seq[Coord] = @[]
  for p in polyLines0:
    poly.add(rotate(p, (0.0, 0.0), angle) * scale + pos)
  discard polygon(poly, color0, DrawMode.filled)

  for i in polyLines1:
    let
      p0 = rotate(i[0], (0.0, 0.0), angle) * scale + pos
      p1 = rotate(i[1], (0.0, 0.0), angle) * scale + pos
    discard aaLine(p0, p1, color1)


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Poly
  scene.poly = newEntity()
  scene.polyG = newProcGraphic()
  scene.polyG.procedure = polyProc
  scene.poly.graphic = scene.polyG
  scene.poly.pos = (320, 240)

  # add to scene
  scene.add(scene.poly)


proc free*(scene: MainScene) =
  discard


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()

  discard box((4, 60), (260, 92), 0x000000CC'u32)

  discard string((8, 64), "WSAD - move", 0xFFFFFFFF'u32)
  discard string((8, 72), "QE   - rotate", 0xFFFFFFFF'u32)
  discard string((8, 80), "RF   - scale", 0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if ScancodeA.down: scene.poly.pos.x -= 1
  if ScancodeD.down: scene.poly.pos.x += 1
  if ScancodeW.down: scene.poly.pos.y -= 1
  if ScancodeS.down: scene.poly.pos.y += 1
  if ScancodeQ.down: scene.poly.rot -= 1
  if ScancodeE.down: scene.poly.rot += 1
  if ScancodeR.down: scene.poly.scale -= 0.01
  if ScancodeF.down: scene.poly.scale += 0.01



================================================
FILE: demos/demo9/README.md
================================================
Nimgame 2: Demo 9
=================

Audio demo. Demonstrates sound effects.

![Screenshot](demo9.png)



================================================
FILE: demos/demo9/demo9.nim
================================================
import
  nimgame2/nimgame,
  nimgame2/settings,
  nimgame2/assets,
  nimgame2/texturegraphic,
  mainscene

game = newGame()
if game.init(w = 640, h = 480, title = "Nimgame 2: Demo 9 (Audio)",
             scaleQuality = 0):
  showInfo = true
  game.scene = newMainScene()
  game.run()



================================================
FILE: demos/demo9/mainscene.nim
================================================
import
  math,
  nimgame2/assets,
  nimgame2/audio,
  nimgame2/nimgame,
  nimgame2/draw,
  nimgame2/input,
  nimgame2/scene,
  nimgame2/settings,
  nimgame2/types,
  nimgame2/utils


type
  MainScene = ref object of Scene
    tack: Sound


var
  musicData: Assets[Music]


proc init*(scene: MainScene) =
  Scene(scene).init()

  # Sound
  scene.tack = newSound("../assets/sfx/tack.wav")
  scene.tack.volume = Volume.high div 2

  # Music
  musicData = newAssets[Music]("../assets/mus",
    proc(file: string): Music = newMusic(file))
  playlist = newPlaylist()
  for track in musicData.values:
    playlist.list.add(track)


proc free*(scene: MainScene) =
  discard


proc newMainScene*(): MainScene =
  new result, free
  result.init()


method event*(scene: MainScene, event: Event) =
  if event.kind == KeyDown:
    case event.key.keysym.sym:
    of K_Escape:
      gameRunning = false
    of K_Space:
      discard scene.tack.play()
    of K_M:
      discard playlist.play()
    else: discard


method render*(scene: MainScene) =
  scene.renderScene()

  discard box((4, 60), (260, 92), 0x000000CC'u32)

  discard string((8, 64), "Space - play sound", 0xFFFFFFFF'u32)
  discard string((8, 72),
    "Up/Down - sound volume: " & $scene.tack.volume, 0xFFFFFFFF'u32)
  discard string((8, 80), "M - play random music track", 0xFFFFFFFF'u32)
  discard string((8, 88),
    "PgUp/PgDn - music volume: " & $getMusicVolume(), 0xFFFFFFFF'u32)


method update*(scene: MainScene, elapsed: float) =
  scene.updateScene(elapsed)
  if ScancodeUp.down: scene.tack.volumeInc(1)
  if ScancodeDown.down: scene.tack.volumeDec(1)
  if ScancodePageUp.down: musicVolumeInc(1)
  if ScancodePageDown.down: musicVolumeDec(1)



================================================
FILE: demos/nim.cfg
================================================
--multimethods:on


================================================
FILE: docs/changelog.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>

    <title>Nimgame 2</title>

    <link rel="stylesheet" type="text/css" href="style.css" media="screen"/>
</head>
<body>

<noscript>This site needs JavaScript to work properly.</noscript>

<header>
</header>

<main>
    <aside>

    </aside>


    <article>
        <h2>CHANGELOG</h2>

        <h3>v0.5 alpha (2017-08-01)</h3>
        <ul>
            <li>changed physics and logic systems</li>
            <li>platformer physics</li>
            <li>CoordInt type</li>
            <li>now collider module is autmatically included into the entity module</li>
            <li>group collider</li>
            <li>huge Tilemap optimizations</li>
            <li>various utility Tilemap procedures</li>
            <li>TextureGraphic.drawTiled</li>
            <li>GUI:
                <ul>
                    <li>GUIProgressBar</li>
                    <li>widget actions</li>
                </ul>
            </li>
            <li>various minor changes and upgrades</li>
            <li>Nim v0.17.0 transition</li>
            <li>documentation, snippets, and demos update</li>
            <li>
                <a href="tut102_platformer.html">
                    second tutorial
                </a>
        </ul>

        <h3>v0.4 alpha (2017-05-04)</h3>
        <ul>
            <li>GUI:
                <ul>
                    <li>RadioGroup</li>
                    <li>RadioButton</li>
                </ul>
            </li>
            <li>IndexedImage</li>
            <li>PerspectiveImage</li>
            <li>TextureAtlas</li>
            <li>joysticks support</li>
            <li>window management procedures</li>
            <li>4 new demos</li>
            <li>
                <a href="tut101_bounce.html">
                   first tutorial
                </a>
            </li>
        </ul>

    <h3>v0.3 alpha (2017-03-10)</h3>

    <ul>
        <li>camera property (Scene)</li>
        <li>new collision procedures</li>
        <li>reworked input</li>
        <li>Mosaic</li>
        <li>parallax property (Entity)</li>
        <li>TextField</li>
        <li>GUI:
            <ul>
                <li>Widget</li>
                <li>Button</li>
                <li>TextInput</li>
            </ul>
        </li>
        <li>3 new demos</li>
        <li>home page, snippets, and documentation</li>
    </ul>

    <h3>v0.2 alpha (2017-01-31)</h3>

    <ul>
        <li>collider optimizations</li>
        <li>music playlists</li>
        <li>random procedures</li>
        <li>tilemaps</li>
        <li>tweens</li>
        <li>emitters</li>
        <li>various fixes</li>
        <li>4 new demos</li>
    </ul>

    <h3>v0.1 alpha (2017-01-16)</h3>

    <ul>
        <li>base scene/entity system</li>
        <li>assets manager</li>
        <li>basic sound and music</li>
        <li>colliders (point, box, circle, line, and polygon)</li>
        <li>fonts (bitmap and TrueType) and text output</li>
        <li>keyboard and mouse input</li>
        <li>vector drawing procedures</li>
    </ul>

    </article>

</main>

<footer>
</footer>

<script src="structure.js"></script>

</body>
</html>



================================================
FILE: docs/demos.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>

    <title>Nimgame 2</title>

    <link rel="stylesheet" type="text/css" href="style.css" media="screen"/>
</head>
<body>

<noscript>This site needs JavaScript to work properly.</noscript>

<header>
</header>

<main>
    <aside>
    </aside>

    <article>
        <h2>DEMOS</h2>

        <h3>Game Demos</h3>
        <ul>
            <li>
                <a href="https://github.com/Vladar4/ng2gggrotto"
                   target="_blank">
                    Glorious Glacier Grotto
                </a>
            </li>
            <li>
                <a href="https://github.com/Vladar4/ng2planetoids"
                   target="_blank">
                    Planetoids
                </a>
            </li>
        </ul>

        <h3>Feature Demos</h3>
        <ul>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo1"
                   target="_blank">
                    Demo 1
                </a>
                &nbsp;Performance
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo2"
                   target="_blank">
                    Demo 2
                </a>
                &nbsp;Graphic
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo3"
                   target="_blank">
                    Demo 3
                </a>
                &nbsp;Input
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo4"
                   target="_blank">
                    Demo 4
                </a>
                &nbsp;Sprite
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo5"
                   target="_blank">
                    Demo 5
                </a>
                &nbsp;Colliders
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo6"
                   target="_blank">
                    Demo 6
                </a>
                &nbsp;Grouping
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo7"
                   target="_blank">
                    Demo 7
                </a>
                &nbsp;Text
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo8"
                   target="_blank">
                    Demo 8
                </a>
                &nbsp;ProcGraphic
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo9"
                   target="_blank">
                    Demo 9
                </a>
                &nbsp;Audio
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo10"
                   target="_blank">
                    Demo 10
                </a>
                &nbsp;Layers
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo11"
                   target="_blank">
                    Demo 11
                </a>
                &nbsp;Tweens
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo12"
                   target="_blank">
                    Demo 12
                </a>
                &nbsp;Emitters
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo13"
                   target="_blank">
                    Demo 13
                </a>
                &nbsp;TileMaps
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo14"
                   target="_blank">
                    Demo 14
                </a>
                &nbsp;TileMaps, Tweens, Emitters
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo15"
                   target="_blank">
                    Demo 15
                </a>
                &nbsp;Camera
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo16"
                   target="_blank">
                    Demo 16
                </a>
                &nbsp;Parallax
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo17"
                   target="_blank">
                    Demo 17
                </a>
                &nbsp;GUI (Buttons, TextInput)
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo18"
                   target="_blank">
                    Demo 18
                </a>
                &nbsp;IndexedImage
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo19"
                   target="_blank">
                    Demo 19
                </a>
                &nbsp;PerspectiveImage
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo20"
                   target="_blank">
                    Demo 20
                </a>
                &nbsp;TextureAtlas
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo21"
                   target="_blank">
                    Demo 21
                </a>
                &nbsp;Joysticks
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo22"
                   target="_blank">
                    Demo 22
                </a>
                &nbsp;MpegGraphic
            </li>
            <li>
                <a href="https://github.com/Vladar4/nimgame2/tree/master/demos/demo23"
                   target="_blank">
                    Demo 23
                </a>
                &nbsp;Transform
            </li>
        </ul>
    </article>
</main>

<footer>
</footer>

<script src="structure.js"></script>

</body>
</html>



================================================
FILE: docs/docs/assets.html
================================================
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--  This file is generated by Nim. -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- Favicon -->
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>

<!-- Google fonts -->
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>

<!-- CSS -->
<title>assets</title>
<style type="text/css" >
/*
Stylesheet for use with Docutils/rst2html.

See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.

Modified from Chad Skeeters' rst2html-style
https://bitbucket.org/cskeeters/rst2html-style/

Modified by Boyd Greenfield
*/
/* SCSS variables */
/* Text weights */
/* Body colors */
/* Text colors */
/* Link colors */
/* Syntax highlighting colors */
/* Pct changes */
/* Mixins */
/* Body/layout */
html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%; }

/* Where we want fancier font if available */
h1, h2, h3, h4, h5, h6, p.module-desc, table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; }

h1.title {
  font-weight: 900; }

body {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: 400;
  font-size: 16px;
  line-height: 20px;
  color: #444;
  letter-spacing: 0.15px;
  background-color: #FDFBFA; }

/* Skeleton grid */
.container {
  position: relative;
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0 20px;
  box-sizing: border-box; }

.column,
.columns {
  width: 100%;
  float: left;
  box-sizing: border-box; }

/* For devices larger than 400px */
@media (min-width: 400px) {
  .container {
    width: 100%;
    padding: 0; } }
/* For devices larger than 650px */
@media (min-width: 650px) {
  .container {
    width: 100%; }

  .column,
  .columns {
    margin-left: 4%; }

  .column:first-child,
  .columns:first-child {
    margin-left: 0; }

  .one.column,
  .one.columns {
    width: 4.66666666667%; }

  .two.columns {
    width: 13.3333333333%; }

  .three.columns {
    width: 22%; }

  .four.columns {
    width: 30.6666666667%; }

  .five.columns {
    width: 39.3333333333%; }

  .six.columns {
    width: 48%; }

  .seven.columns {
    width: 56.6666666667%; }

  .eight.columns {
    width: 65.3333333333%; }

  .nine.columns {
    width: 74.0%; }

  .ten.columns {
    width: 82.6666666667%; }

  .eleven.columns {
    width: 91.3333333333%; }

  .twelve.columns {
    width: 100%;
    margin-left: 0; }

  .one-third.column {
    width: 30.6666666667%; }

  .two-thirds.column {
    width: 65.3333333333%; } }
/* Customer Overrides */
.footer {
  text-align: center;
  color: #969696;
  padding-top: 10%; }

p.module-desc {
  font-size: 1.1em;
  color: #666666; }

a.link-seesrc {
  color: #aec7d2;
  font-style: italic; }

a.link-seesrc:hover {
  color: #6c9aae; }

#toc-list {
  word-wrap: break-word; }

ul.simple-toc {
  list-style: none; }

ul.simple-toc a.reference-toplevel {
  font-weight: bold;
  color: #0077b3; }

ul.simple-toc-section {
  list-style-type: circle;
  color: #6c9aae; }

ul.simple-toc-section a.reference {
  color: #0077b3; }

cite {
  font-style: italic !important; }

dt > pre {
  border-color: rgba(0, 0, 0, 0.1);
  background-color: rgba(255, 255, 255, 0.3);
  margin: 15px 0px 5px; }

dd > pre {
  border-color: rgba(0, 0, 0, 0.1);
  background-color: whitesmoke;
  margin-top: 8px; }

.item > dd {
  margin-left: 10px;
  margin-bottom: 30px; }

/* Nim line-numbered tables */
.line-nums-table {
  width: 100%;
  table-layout: fixed; }

/* Nim search input */
div#searchInputDiv {
  margin-bottom: 8px;
}
div#searchInputDiv input#searchInput {
  width: 10em;
}
div.search-groupby {
  margin-bottom: 8px;
}

table.line-nums-table {
  border-radius: 4px;
  border: 1px solid #cccccc;
  background-color: whitesmoke;
  border-collapse: separate;
  margin-top: 15px;
  margin-bottom: 25px; }

.line-nums-table tbody {
  border: none; }

.line-nums-table td pre {
  border: none;
  background-color: transparent; }

.line-nums-table td.blob-line-nums {
  width: 28px; }

.line-nums-table td.blob-line-nums pre {
  color: #b0b0b0;
  -webkit-filter: opacity(75%);
  text-align: right;
  border-color: transparent;
  background-color: transparent;
  padding-left: 0px;
  margin-left: 0px;
  padding-right: 0px;
  margin-right: 0px; }

/* Docgen styles */
/* Links */
a {
  color: #0077b3;
  text-decoration: none; }

a:hover,
a:focus {
  color: #00334d;
  text-decoration: underline; }

a:visited {
  color: #00334d; }

a:focus {
  outline: thin dotted #2d2d2d;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px; }

a:hover,
a:active {
  outline: 0; }

sub,
sup {
  position: relative;
  font-size: 75%;
  line-height: 0;
  vertical-align: baseline; }

sup {
  top: -0.5em; }

sub {
  bottom: -0.25em; }

img {
  width: auto;
  height: auto;
  max-width: 100%;
  vertical-align: middle;
  border: 0;
  -ms-interpolation-mode: bicubic; }

@media print {
  * {
    color: black !important;
    text-shadow: none !important;
    background: transparent !important;
    box-shadow: none !important; }

  a,
  a:visited {
    text-decoration: underline; }

  a[href]:after {
    content: " (" attr(href) ")"; }

  abbr[title]:after {
    content: " (" attr(title) ")"; }

  .ir a:after,
  a[href^="javascript:"]:after,
  a[href^="#"]:after {
    content: ""; }

  pre,
  blockquote {
    border: 1px solid #999;
    page-break-inside: avoid; }

  thead {
    display: table-header-group; }

  tr,
  img {
    page-break-inside: avoid; }

  img {
    max-width: 100% !important; }

  @page {
    margin: 0.5cm; }

  h1 {
    page-break-before: always; }

  h1.title {
    page-break-before: avoid; }

  p,
  h2,
  h3 {
    orphans: 3;
    widows: 3; }

  h2,
  h3 {
    page-break-after: avoid; } }
.img-rounded {
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px; }

.img-polaroid {
  padding: 4px;
  background-color: rgba(252, 248, 244, 0.75);
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.2);
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }

p {
  margin: 0 0 8px; }

small {
  font-size: 85%; }

strong {
  font-weight: 600; }

em {
  font-style: italic; }

cite {
  font-style: normal; }

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: 600;
  line-height: 20px;
  color: inherit;
  text-rendering: optimizelegibility; }

h1 {
  font-size: 2em;
  font-weight: 400;
  padding-bottom: .15em;
  border-bottom: 1px solid #aaaaaa;
  margin-top: 1.0em;
  line-height: 1.2em; }

h1.title {
  padding-bottom: 1em;
  border-bottom: 0px;
  font-size: 2.75em; }

h2 {
  font-size: 1.5em;
  margin-top: 1.5em; }

h3 {
  font-size: 1.3em;
  font-style: italic;
  margin-top: 0.75em; }

h4 {
  font-size: 1.3em;
  margin-top: 0.5em; }

h5 {
  font-size: 1.2em;
  margin-top: 0.25em; }

h6 {
  font-size: 1.1em; }

ul,
ol {
  padding: 0;
  margin: 0 0 0px 15px; }

ul ul,
ul ol,
ol ol,
ol ul {
  margin-bottom: 0; }

li {
  line-height: 20px; }

dl {
  margin-bottom: 20px; }

dt,
dd {
  line-height: 20px; }

dt {
  font-weight: bold; }

dd {
  margin-left: 10px;
  margin-bottom: 26px; }

hr {
  margin: 20px 0;
  border: 0;
  border-top: 1px solid #eeeeee;
  border-bottom: 1px solid #ffffff; }

abbr[title],
abbr[data-original-title] {
  cursor: help;
  border-bottom: 1px dotted #999999; }

abbr.initialism {
  font-size: 90%;
  text-transform: uppercase; }

blockquote {
  padding: 0 0 0 15px;
  margin: 0 0 20px;
  border-left: 5px solid #EFEBE0; }

table.docinfo + blockquote, table.docinfo blockquote, h1 + blockquote {
  border-left: 5px solid #c9c9c9;
}

table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
  margin-bottom: 0;
  font-size: 15px;
  font-weight: 200;
  line-height: 1.5;
  font-style: italic; }

q:before,
q:after,
blockquote:before,
blockquote:after {
  content: ""; }

address {
  display: block;
  margin-bottom: 20px;
  font-style: normal;
  line-height: 20px; }

code,
pre {
  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
  padding: 0 3px 2px;
  font-weight: 500;
  font-size: 12px;
  color: #444444;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px; }

.pre {
  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
  font-weight: 600;
  /*color: #504da6;*/
}

code {
  padding: 2px 4px;
  color: #444444;
  white-space: nowrap;
  background-color: white;
  border: 1px solid #777777; }

pre {
  display: inline-block;
  box-sizing: border-box;
  min-width: calc(100% - 19.5px);
  padding: 9.5px;
  margin: 0.25em 10px 10px 10px;
  font-size: 15px;
  line-height: 20px;
  white-space: pre !important;
  overflow-y: hidden;
  overflow-x: visible;
  background-color: rgba(0, 0, 0, 0.01);
  border: 1px solid #cccccc;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px; }

pre.prettyprint {
  margin-bottom: 20px; }

pre code {
  padding: 0;
  color: inherit;
  white-space: pre;
  overflow-x: visible;
  background-color: transparent;
  border: 0; }

.pre-scrollable {
  max-height: 340px;
  overflow-y: scroll; }

table {
  max-width: 100%;
  background-color: transparent;
  border-collapse: collapse;
  border-spacing: 0; }

table th, table td {
  padding: 0px 8px 0px;
}

.table {
  width: 100%;
  margin-bottom: 20px; }

.table th,
.table td {
  padding: 8px;
  line-height: 20px;
  text-align: left;
  vertical-align: top;
  border-top: 1px solid #444444; }

.table th {
  font-weight: bold; }

.table thead th {
  vertical-align: bottom; }

.table caption + thead tr:first-child th,
.table caption + thead tr:first-child td,
.table colgroup + thead tr:first-child th,
.table colgroup + thead tr:first-child td,
.table thead:first-child tr:first-child th,
.table thead:first-child tr:first-child td {
  border-top: 0; }

.table tbody + tbody {
  border-top: 2px solid #444444; }

.table .table {
  background-color: rgba(252, 248, 244, 0.75); }

.table-condensed th,
.table-condensed td {
  padding: 4px 5px; }

.table-bordered {
  border: 1px solid #444444;
  border-collapse: separate;
  *border-collapse: collapse;
  border-left: 0;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px; }

.table-bordered th,
.table-bordered td {
  border-left: 1px solid #444444; }

.table-bordered caption + thead tr:first-child th,
.table-bordered caption + tbody tr:first-child th,
.table-bordered caption + tbody tr:first-child td,
.table-bordered colgroup + thead tr:first-child th,
.table-bordered colgroup + tbody tr:first-child th,
.table-bordered colgroup + tbody tr:first-child td,
.table-bordered thead:first-child tr:first-child th,
.table-bordered tbody:first-child tr:first-child th,
.table-bordered tbody:first-child tr:first-child td {
  border-top: 0; }

.table-bordered thead:first-child tr:first-child > th:first-child,
.table-bordered tbody:first-child tr:first-child > td:first-child,
.table-bordered tbody:first-child tr:first-child > th:first-child {
  -webkit-border-top-left-radius: 4px;
  border-top-left-radius: 4px;
  -moz-border-radius-topleft: 4px; }

.table-bordered thead:first-child tr:first-child > th:last-child,
.table-bordered tbody:first-child tr:first-child > td:last-child,
.table-bordered tbody:first-child tr:first-child > th:last-child {
  -webkit-border-top-right-radius: 4px;
  border-top-right-radius: 4px;
  -moz-border-radius-topright: 4px; }

.table-bordered thead:last-child tr:last-child > th:first-child,
.table-bordered tbody:last-child tr:last-child > td:first-child,
.table-bordered tbody:last-child tr:last-child > th:first-child,
.table-bordered tfoot:last-child tr:last-child > td:first-child,
.table-bordered tfoot:last-child tr:last-child > th:first-child {
  -webkit-border-bottom-left-radius: 4px;
  border-bottom-left-radius: 4px;
  -moz-border-radius-bottomleft: 4px; }

.table-bordered thead:last-child tr:last-child > th:last-child,
.table-bordered tbody:last-child tr:last-child > td:last-child,
.table-bordered tbody:last-child tr:last-child > th:last-child,
.table-bordered tfoot:last-child tr:last-child > td:last-child,
.table-bordered tfoot:last-child tr:last-child > th:last-child {
  -webkit-border-bottom-right-radius: 4px;
  border-bottom-right-radius: 4px;
  -moz-border-radius-bottomright: 4px; }

.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
  -webkit-border-bottom-left-radius: 0;
  border-bottom-left-radius: 0;
  -moz-border-radius-bottomleft: 0; }

.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
  -webkit-border-bottom-right-radius: 0;
  border-bottom-right-radius: 0;
  -moz-border-radius-bottomright: 0; }

.table-bordered caption + thead tr:first-child th:first-child,
.table-bordered caption + tbody tr:first-child td:first-child,
.table-bordered colgroup + thead tr:first-child th:first-child,
.table-bordered colgroup + tbody tr:first-child td:first-child {
  -webkit-border-top-left-radius: 4px;
  border-top-left-radius: 4px;
  -moz-border-radius-topleft: 4px; }

.table-bordered caption + thead tr:first-child th:last-child,
.table-bordered caption + tbody tr:first-child td:last-child,
.table-bordered colgroup + thead tr:first-child th:last-child,
.table-bordered colgroup + tbody tr:first-child td:last-child {
  -webkit-border-top-right-radius: 4px;
  border-top-right-radius: 4px;
  -moz-border-radius-topright: 4px; }

table.docutils th {
  background-color: #e8e8e8; }

table.docutils tr:hover {
  background-color: whitesmoke; }

.table-striped tbody > tr:nth-child(odd) > td,
.table-striped tbody > tr:nth-child(odd) > th {
  background-color: rgba(252, 248, 244, 0.75); }

.table-hover tbody tr:hover > td,
.table-hover tbody tr:hover > th {
  background-color: rgba(241, 222, 204, 0.75); }

table td[class*="span"],
table th[class*="span"],
.row-fluid table td[class*="span"],
.row-fluid table th[class*="span"] {
  display: table-cell;
  float: none;
  margin-left: 0; }

.hero-unit {
  padding: 60px;
  margin-bottom: 30px;
  font-size: 18px;
  font-weight: 200;
  line-height: 30px;
  color: inherit;
  background-color: rgba(230, 197, 164, 0.75);
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px; }

.hero-unit h1 {
  margin-bottom: 0;
  font-size: 60px;
  line-height: 1;
  letter-spacing: -1px;
  color: inherit; }

.hero-unit li {
  line-height: 30px; }

/* rst2html default used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
  border: 0; }

table.borderless td, table.borderless th {
  /* Override padding for "table.docutils td" with "! important".
     The right padding separates the table cells. */
  padding: 0 0.5em 0 0 !important; }

.first {
  /* Override more specific margin styles with "! important". */
  margin-top: 0 !important; }

.last, .with-subtitle {
  margin-bottom: 0 !important; }

.hidden {
  display: none; }

a.toc-backref {
  text-decoration: none;
  color: #444444; }

blockquote.epigraph {
  margin: 2em 5em; }

dl.docutils dd {
  margin-bottom: 0.5em; }

object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
  overflow: hidden; }

/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
  font-weight: bold }
*/
div.abstract {
  margin: 2em 5em; }

div.abstract p.topic-title {
  font-weight: bold;
  text-align: center; }

div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
  margin: 2em;
  border: medium outset;
  padding: 1em; }

div.note, div.warning {
  margin: 1.5em 0px;
  border: none; }

div.note p.admonition-title,
div.warning p.admonition-title {
  display: none; }

/* Clearfix
 * http://css-tricks.com/snippets/css/clear-fix/
 */
div.note:after,
div.warning:after {
  content: "";
  display: table;
  clear: both; }

div.note p:before,
div.warning p:before {
  display: block;
  float: left;
  font-size: 4em;
  line-height: 1em;
  margin-right: 20px;
  margin-left: 0em;
  margin-top: -10px;
  content: '\0270D';
  /*handwriting*/ }

div.warning p:before {
  content: '\026A0';
  /*warning*/ }

div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
  font-weight: bold;
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
  color: #b30000;
  font-weight: bold;
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }

/* Uncomment (and remove this text!) to get reduced vertical space in
   compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
  margin-bottom: 0.5em }

div.compound .compound-last, div.compound .compound-middle {
  margin-top: 0.5em }
*/
div.dedication {
  margin: 2em 5em;
  text-align: center;
  font-style: italic; }

div.dedication p.topic-title {
  font-weight: bold;
  font-style: normal; }

div.figure {
  margin-left: 2em;
  margin-right: 2em; }

div.footer, div.header {
  clear: both;
  font-size: smaller; }

div.line-block {
  display: block;
  margin-top: 1em;
  margin-bottom: 1em; }

div.line-block div.line-block {
  margin-top: 0;
  margin-bottom: 0;
  margin-left: 1.5em; }

div.sidebar {
  margin: 0 0 0.5em 1em;
  border: medium outset;
  padding: 1em;
  background-color: rgba(252, 248, 244, 0.75);
  width: 40%;
  float: right;
  clear: right; }

div.sidebar p.rubric {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-size: medium; }

div.system-messages {
  margin: 5em; }

div.system-messages h1 {
  color: #b30000; }

div.system-message {
  border: medium outset;
  padding: 1em; }

div.system-message p.system-message-title {
  color: #b30000;
  font-weight: bold; }

div.topic {
  margin: 2em; }

h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  margin-top: 0.4em; }

h1.title {
  text-align: center; }

h2.subtitle {
  text-align: center; }

hr.docutils {
  width: 75%; }

img.align-left, .figure.align-left, object.align-left {
  clear: left;
  float: left;
  margin-right: 1em; }

img.align-right, .figure.align-right, object.align-right {
  clear: right;
  float: right;
  margin-left: 1em; }

img.align-center, .figure.align-center, object.align-center {
  display: block;
  margin-left: auto;
  margin-right: auto; }

.align-left {
  text-align: left; }

.align-center {
  clear: both;
  text-align: center; }

.align-right {
  text-align: right; }

/* reset inner alignment in figures */
div.align-right {
  text-align: inherit; }

/* div.align-center * { */
/*   text-align: left } */

ul.simple > li {
  margin-bottom: 0.5em }

ol.simple, ul.simple {
  margin-bottom: 1em; }

ol.arabic {
  list-style: decimal; }

ol.loweralpha {
  list-style: lower-alpha; }

ol.upperalpha {
  list-style: upper-alpha; }

ol.lowerroman {
  list-style: lower-roman; }

ol.upperroman {
  list-style: upper-roman; }

p.attribution {
  text-align: right;
  margin-left: 50%; }

p.caption {
  font-style: italic; }

p.credits {
  font-style: italic;
  font-size: smaller; }

p.label {
  white-space: nowrap; }

p.rubric {
  font-weight: bold;
  font-size: larger;
  color: maroon;
  text-align: center; }

p.sidebar-title {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: bold;
  font-size: larger; }

p.sidebar-subtitle {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: bold; }

p.topic-title {
  font-weight: bold; }

pre.address {
  margin-bottom: 0;
  margin-top: 0;
  font: inherit; }

pre.literal-block, pre.doctest-block, pre.math, pre.code {
  margin-left: 2em;
  margin-right: 2em; }

pre.code .ln {
  color: grey; }

/* line numbers */
pre.code, code {
  background-color: #eeeeee; }

pre.code .comment, code .comment {
  color: #5c6576; }

pre.code .keyword, code .keyword {
  color: #3B0D06;
  font-weight: bold; }

pre.code .literal.string, code .literal.string {
  color: #0c5404; }

pre.code .name.builtin, code .name.builtin {
  color: #352b84; }

pre.code .deleted, code .deleted {
  background-color: #DEB0A1; }

pre.code .inserted, code .inserted {
  background-color: #A3D289; }

span.classifier {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-style: oblique; }

span.classifier-delimiter {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: bold; }

span.interpreted {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }

span.option {
  white-space: nowrap; }

span.pre {
  white-space: pre; }

span.problematic {
  color: #b30000; }

span.section-subtitle {
  /* font-size relative to parent (h1..h6 element) */
  font-size: 80%; }

table.citation {
  border-left: solid 1px #666666;
  margin-left: 1px; }

table.docinfo {
  margin: 0em;
  margin-top: 2em;
  margin-bottom: 2em;
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important;
  color: #444444; }

table.docutils {
  margin-top: 0.5em;
  margin-bottom: 0.5em; }

table.footnote {
  border-left: solid 1px #2d2d2d;
  margin-left: 1px; }

table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
  padding-left: 0.5em;
  padding-right: 0.5em;
  vertical-align: top; }

table.docutils th.field-name, table.docinfo th.docinfo-name {
  font-weight: 700;
  text-align: left;
  white-space: nowrap;
  padding-left: 0; }

h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  font-size: 100%; }

ul.auto-toc {
  list-style-type: none; }

span.DecNumber {
  color: #252dbe; }

span.BinNumber {
  color: #252dbe; }

span.HexNumber {
  color: #252dbe; }

span.OctNumber {
  color: #252dbe; }

span.FloatNumber {
  color: #252dbe; }

span.Identifier {
  color: #3b3b3b; }

span.Keyword {
  font-weight: 600;
  color: #5e8f60; }

span.StringLit {
  color: #a4255b; }

span.LongStringLit {
  color: #a4255b; }

span.CharLit {
  color: #a4255b; }

span.EscapeSequence {
  color: black; }

span.Operator {
  color: black; }

span.Punctuation {
  color: black; }

span.Comment, span.LongComment {
  font-style: italic;
  font-weight: 400;
  color: #484a86; }

span.RegularExpression {
  color: darkviolet; }

span.TagStart {
  color: darkviolet; }

span.TagEnd {
  color: darkviolet; }

span.Key {
  color: #252dbe; }

span.Value {
  color: #252dbe; }

span.RawData {
  color: #a4255b; }

span.Assembler {
  color: #252dbe; }

span.Preprocessor {
  color: #252dbe; }

span.Directive {
  color: #252dbe; }

span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
span.Other {
  color: black; }

/* Pop type, const, proc, and iterator defs in nim def blocks */
dt pre > span.Identifier, dt pre > span.Operator {
  color: #155da4;
  font-weight: 700; }

dt pre > span.Identifier ~ span.Identifier, dt pre > span.Operator ~ span.Identifier {
  color: inherit;
  font-weight: inherit; }

dt pre > span.Operator ~ span.Identifier {
  color: inherit;
  font-weight: inherit; }

/* Nim sprite for the footer (taken from main page favicon) */
.nim-sprite {
  display: inline-block;
  height: 12px;
  width: 12px;
  background-position: 0 0;
  background-size: 12px 12px;
  -webkit-filter: opacity(50%);
  background-repeat: no-repeat;
  background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
  margin-bottom: -5px; }

div.search_results {
  background-color: antiquewhite;
  margin: 3em;
  padding: 1em;
  border: 1px solid #4d4d4d;
}

div#global-links ul {
  margin-left: 0;
  list-style-type: none;
}

span.pragmadots {
  /* Position: relative frees us up to make the dots
  look really nice without fucking up the layout and
  causing bulging in the parent container */
  position: relative;
  /* 1px down looks slightly nicer */
  top: 1px;

  padding: 2px;
  background-color: #D3D3D3;
  border-radius: 4px;
  margin: 0 2px;
  cursor: pointer;

  /* For some reason on Chrome, making the font size
  smaller than 1em is causing the parent container to
  bulge slightly. So, we're stuck with inheriting 1em,
  which is sad, because 0.8em looks better... */
}
span.pragmadots:hover {
  background-color: #DBDBDB;
}
span.pragmawrap {
  display: none;
}

</style>

<script type="text/javascript" src="dochack.js"></script>

<script type="text/javascript">
function main() {
  var pragmaDots = document.getElementsByClassName("pragmadots");
  for (var i = 0; i < pragmaDots.length; i++) {
    pragmaDots[i].onclick = function(event) {
      // Hide tease
      event.target.parentNode.style.display = "none";
      // Show actual
      event.target.parentNode.nextElementSibling.style.display = "inline";
    }
  }
}
</script>

</head>
<body onload="main()">
<div class="document" id="documentId">
  <div class="container">
    <h1 class="title">assets</h1>
    <div class="row">
  <div class="three columns">
  <div id="global-links">
    <ul class="simple">
    </ul>
  </div>
  <div id="searchInputDiv">
    Search: <input type="text" id="searchInput"
      onkeyup="search()" />
  </div>
  <div>
    Group by:
    <select onchange="groupBy(this.value)">
      <option value="section">Section</option>
      <option value="type">Type</option>
    </select>
  </div>
  <ul class="simple simple-toc" id="toc-list">
<li>
  <a class="reference reference-toplevel" href="#7" id="57">Types</a>
  <ul class="simple simple-toc-section">
      <li><a class="reference" href="#Assets"
    title="Assets[T] = OrderedTableRef[string, T]"><wbr />Assets<span class="attachedType" style="visibility:hidden"></span></a></li>

  </ul>
</li>
<li>
  <a class="reference reference-toplevel" href="#12" id="62">Procs</a>
  <ul class="simple simple-toc-section">
      <li><a class="reference" href="#newAssets%2CopenArray%5Bstring%5D%2Cproc%28string%29"
    title="newAssets[T](files: openArray[string]; init: proc (file: string): T): Assets[T]"><wbr />new<wbr />Assets<span class="attachedType" style="visibility:hidden">Assets</span></a></li>
  <li><a class="reference" href="#newAssets%2Cstring%2Cproc%28string%29"
    title="newAssets[T](dir: string; init: proc (file: string): T): Assets[T]"><wbr />new<wbr />Assets<span class="attachedType" style="visibility:hidden">Assets</span></a></li>

  </ul>
</li>

</ul>

  </div>
  <div class="nine columns" id="content">
  <div id="tocRoot"></div>
  <p class="module-desc"></p>
  <div class="section" id="7">
<h1><a class="toc-backref" href="#7">Types</a></h1>
<dl class="item">
<a id="Assets"></a>
<dt><pre><a href="assets.html#Assets"><span class="Identifier">Assets</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span> <span class="Other">=</span> <span class="Identifier">OrderedTableRef</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">,</span> <span class="Identifier">T</span><span class="Other">]</span></pre></dt>
<dd>


</dd>

</dl></div>
<div class="section" id="12">
<h1><a class="toc-backref" href="#12">Procs</a></h1>
<dl class="item">
<a id="newAssets,openArray[string],proc(string)"></a>
<dt><pre><span class="Keyword">proc</span> <span class="Identifier">newAssets</span><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">files</span><span class="Other">:</span> <span class="Identifier">openArray</span><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">;</span> <span class="Identifier">init</span><span class="Other">:</span> <span class="Keyword">proc</span> <span class="Other">(</span><span class="Identifier">file</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <a href="assets.html#Assets"><span class="Identifier">Assets</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span></pre></dt>
<dd>
<p>Create a new assets collection.</p>
<p><tt class="docutils literal"><span class="pre">files</span></tt> an array of target files.</p>
<p><tt class="docutils literal"><span class="pre">init</span></tt> <tt class="docutils literal"><span class="pre">T</span></tt>'s init/load procedure. </p>


</dd>
<a id="newAssets,string,proc(string)"></a>
<dt><pre><span class="Keyword">proc</span> <span class="Identifier">newAssets</span><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">dir</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">;</span> <span class="Identifier">init</span><span class="Other">:</span> <span class="Keyword">proc</span> <span class="Other">(</span><span class="Identifier">file</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <a href="assets.html#Assets"><span class="Identifier">Assets</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span></pre></dt>
<dd>
<p>Create a new assets collection.</p>
<p><tt class="docutils literal"><span class="pre">dir</span></tt> target directory.</p>
<p><tt class="docutils literal"><span class="pre">init</span></tt> <tt class="docutils literal"><span class="pre">T</span></tt>'s init/load procedure. </p>


</dd>

</dl></div>

  </div>
</div>

    <div class="row">
      <div class="twelve-columns footer">
        <span class="nim-sprite"></span>
        <br/>
        <small>Made with Nim. Generated: 2019-01-21 14:58:31 UTC</small>
      </div>
    </div>
  </div>
</div>

</body>
</html>


================================================
FILE: docs/docs/audio.html
================================================
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--  This file is generated by Nim. -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- Favicon -->
<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>

<!-- Google fonts -->
<link href='https://fonts.googleapis.com/css?family=Lato:400,600,900' rel='stylesheet' type='text/css'/>
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>

<!-- CSS -->
<title>audio</title>
<style type="text/css" >
/*
Stylesheet for use with Docutils/rst2html.

See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.

Modified from Chad Skeeters' rst2html-style
https://bitbucket.org/cskeeters/rst2html-style/

Modified by Boyd Greenfield
*/
/* SCSS variables */
/* Text weights */
/* Body colors */
/* Text colors */
/* Link colors */
/* Syntax highlighting colors */
/* Pct changes */
/* Mixins */
/* Body/layout */
html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%; }

/* Where we want fancier font if available */
h1, h2, h3, h4, h5, h6, p.module-desc, table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; }

h1.title {
  font-weight: 900; }

body {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: 400;
  font-size: 16px;
  line-height: 20px;
  color: #444;
  letter-spacing: 0.15px;
  background-color: #FDFBFA; }

/* Skeleton grid */
.container {
  position: relative;
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0 20px;
  box-sizing: border-box; }

.column,
.columns {
  width: 100%;
  float: left;
  box-sizing: border-box; }

/* For devices larger than 400px */
@media (min-width: 400px) {
  .container {
    width: 100%;
    padding: 0; } }
/* For devices larger than 650px */
@media (min-width: 650px) {
  .container {
    width: 100%; }

  .column,
  .columns {
    margin-left: 4%; }

  .column:first-child,
  .columns:first-child {
    margin-left: 0; }

  .one.column,
  .one.columns {
    width: 4.66666666667%; }

  .two.columns {
    width: 13.3333333333%; }

  .three.columns {
    width: 22%; }

  .four.columns {
    width: 30.6666666667%; }

  .five.columns {
    width: 39.3333333333%; }

  .six.columns {
    width: 48%; }

  .seven.columns {
    width: 56.6666666667%; }

  .eight.columns {
    width: 65.3333333333%; }

  .nine.columns {
    width: 74.0%; }

  .ten.columns {
    width: 82.6666666667%; }

  .eleven.columns {
    width: 91.3333333333%; }

  .twelve.columns {
    width: 100%;
    margin-left: 0; }

  .one-third.column {
    width: 30.6666666667%; }

  .two-thirds.column {
    width: 65.3333333333%; } }
/* Customer Overrides */
.footer {
  text-align: center;
  color: #969696;
  padding-top: 10%; }

p.module-desc {
  font-size: 1.1em;
  color: #666666; }

a.link-seesrc {
  color: #aec7d2;
  font-style: italic; }

a.link-seesrc:hover {
  color: #6c9aae; }

#toc-list {
  word-wrap: break-word; }

ul.simple-toc {
  list-style: none; }

ul.simple-toc a.reference-toplevel {
  font-weight: bold;
  color: #0077b3; }

ul.simple-toc-section {
  list-style-type: circle;
  color: #6c9aae; }

ul.simple-toc-section a.reference {
  color: #0077b3; }

cite {
  font-style: italic !important; }

dt > pre {
  border-color: rgba(0, 0, 0, 0.1);
  background-color: rgba(255, 255, 255, 0.3);
  margin: 15px 0px 5px; }

dd > pre {
  border-color: rgba(0, 0, 0, 0.1);
  background-color: whitesmoke;
  margin-top: 8px; }

.item > dd {
  margin-left: 10px;
  margin-bottom: 30px; }

/* Nim line-numbered tables */
.line-nums-table {
  width: 100%;
  table-layout: fixed; }

/* Nim search input */
div#searchInputDiv {
  margin-bottom: 8px;
}
div#searchInputDiv input#searchInput {
  width: 10em;
}
div.search-groupby {
  margin-bottom: 8px;
}

table.line-nums-table {
  border-radius: 4px;
  border: 1px solid #cccccc;
  background-color: whitesmoke;
  border-collapse: separate;
  margin-top: 15px;
  margin-bottom: 25px; }

.line-nums-table tbody {
  border: none; }

.line-nums-table td pre {
  border: none;
  background-color: transparent; }

.line-nums-table td.blob-line-nums {
  width: 28px; }

.line-nums-table td.blob-line-nums pre {
  color: #b0b0b0;
  -webkit-filter: opacity(75%);
  text-align: right;
  border-color: transparent;
  background-color: transparent;
  padding-left: 0px;
  margin-left: 0px;
  padding-right: 0px;
  margin-right: 0px; }

/* Docgen styles */
/* Links */
a {
  color: #0077b3;
  text-decoration: none; }

a:hover,
a:focus {
  color: #00334d;
  text-decoration: underline; }

a:visited {
  color: #00334d; }

a:focus {
  outline: thin dotted #2d2d2d;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px; }

a:hover,
a:active {
  outline: 0; }

sub,
sup {
  position: relative;
  font-size: 75%;
  line-height: 0;
  vertical-align: baseline; }

sup {
  top: -0.5em; }

sub {
  bottom: -0.25em; }

img {
  width: auto;
  height: auto;
  max-width: 100%;
  vertical-align: middle;
  border: 0;
  -ms-interpolation-mode: bicubic; }

@media print {
  * {
    color: black !important;
    text-shadow: none !important;
    background: transparent !important;
    box-shadow: none !important; }

  a,
  a:visited {
    text-decoration: underline; }

  a[href]:after {
    content: " (" attr(href) ")"; }

  abbr[title]:after {
    content: " (" attr(title) ")"; }

  .ir a:after,
  a[href^="javascript:"]:after,
  a[href^="#"]:after {
    content: ""; }

  pre,
  blockquote {
    border: 1px solid #999;
    page-break-inside: avoid; }

  thead {
    display: table-header-group; }

  tr,
  img {
    page-break-inside: avoid; }

  img {
    max-width: 100% !important; }

  @page {
    margin: 0.5cm; }

  h1 {
    page-break-before: always; }

  h1.title {
    page-break-before: avoid; }

  p,
  h2,
  h3 {
    orphans: 3;
    widows: 3; }

  h2,
  h3 {
    page-break-after: avoid; } }
.img-rounded {
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px; }

.img-polaroid {
  padding: 4px;
  background-color: rgba(252, 248, 244, 0.75);
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.2);
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }

p {
  margin: 0 0 8px; }

small {
  font-size: 85%; }

strong {
  font-weight: 600; }

em {
  font-style: italic; }

cite {
  font-style: normal; }

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: 600;
  line-height: 20px;
  color: inherit;
  text-rendering: optimizelegibility; }

h1 {
  font-size: 2em;
  font-weight: 400;
  padding-bottom: .15em;
  border-bottom: 1px solid #aaaaaa;
  margin-top: 1.0em;
  line-height: 1.2em; }

h1.title {
  padding-bottom: 1em;
  border-bottom: 0px;
  font-size: 2.75em; }

h2 {
  font-size: 1.5em;
  margin-top: 1.5em; }

h3 {
  font-size: 1.3em;
  font-style: italic;
  margin-top: 0.75em; }

h4 {
  font-size: 1.3em;
  margin-top: 0.5em; }

h5 {
  font-size: 1.2em;
  margin-top: 0.25em; }

h6 {
  font-size: 1.1em; }

ul,
ol {
  padding: 0;
  margin: 0 0 0px 15px; }

ul ul,
ul ol,
ol ol,
ol ul {
  margin-bottom: 0; }

li {
  line-height: 20px; }

dl {
  margin-bottom: 20px; }

dt,
dd {
  line-height: 20px; }

dt {
  font-weight: bold; }

dd {
  margin-left: 10px;
  margin-bottom: 26px; }

hr {
  margin: 20px 0;
  border: 0;
  border-top: 1px solid #eeeeee;
  border-bottom: 1px solid #ffffff; }

abbr[title],
abbr[data-original-title] {
  cursor: help;
  border-bottom: 1px dotted #999999; }

abbr.initialism {
  font-size: 90%;
  text-transform: uppercase; }

blockquote {
  padding: 0 0 0 15px;
  margin: 0 0 20px;
  border-left: 5px solid #EFEBE0; }

table.docinfo + blockquote, table.docinfo blockquote, h1 + blockquote {
  border-left: 5px solid #c9c9c9;
}

table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
  margin-bottom: 0;
  font-size: 15px;
  font-weight: 200;
  line-height: 1.5;
  font-style: italic; }

q:before,
q:after,
blockquote:before,
blockquote:after {
  content: ""; }

address {
  display: block;
  margin-bottom: 20px;
  font-style: normal;
  line-height: 20px; }

code,
pre {
  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
  padding: 0 3px 2px;
  font-weight: 500;
  font-size: 12px;
  color: #444444;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px; }

.pre {
  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
  font-weight: 600;
  /*color: #504da6;*/
}

code {
  padding: 2px 4px;
  color: #444444;
  white-space: nowrap;
  background-color: white;
  border: 1px solid #777777; }

pre {
  display: inline-block;
  box-sizing: border-box;
  min-width: calc(100% - 19.5px);
  padding: 9.5px;
  margin: 0.25em 10px 10px 10px;
  font-size: 15px;
  line-height: 20px;
  white-space: pre !important;
  overflow-y: hidden;
  overflow-x: visible;
  background-color: rgba(0, 0, 0, 0.01);
  border: 1px solid #cccccc;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px; }

pre.prettyprint {
  margin-bottom: 20px; }

pre code {
  padding: 0;
  color: inherit;
  white-space: pre;
  overflow-x: visible;
  background-color: transparent;
  border: 0; }

.pre-scrollable {
  max-height: 340px;
  overflow-y: scroll; }

table {
  max-width: 100%;
  background-color: transparent;
  border-collapse: collapse;
  border-spacing: 0; }

table th, table td {
  padding: 0px 8px 0px;
}

.table {
  width: 100%;
  margin-bottom: 20px; }

.table th,
.table td {
  padding: 8px;
  line-height: 20px;
  text-align: left;
  vertical-align: top;
  border-top: 1px solid #444444; }

.table th {
  font-weight: bold; }

.table thead th {
  vertical-align: bottom; }

.table caption + thead tr:first-child th,
.table caption + thead tr:first-child td,
.table colgroup + thead tr:first-child th,
.table colgroup + thead tr:first-child td,
.table thead:first-child tr:first-child th,
.table thead:first-child tr:first-child td {
  border-top: 0; }

.table tbody + tbody {
  border-top: 2px solid #444444; }

.table .table {
  background-color: rgba(252, 248, 244, 0.75); }

.table-condensed th,
.table-condensed td {
  padding: 4px 5px; }

.table-bordered {
  border: 1px solid #444444;
  border-collapse: separate;
  *border-collapse: collapse;
  border-left: 0;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px; }

.table-bordered th,
.table-bordered td {
  border-left: 1px solid #444444; }

.table-bordered caption + thead tr:first-child th,
.table-bordered caption + tbody tr:first-child th,
.table-bordered caption + tbody tr:first-child td,
.table-bordered colgroup + thead tr:first-child th,
.table-bordered colgroup + tbody tr:first-child th,
.table-bordered colgroup + tbody tr:first-child td,
.table-bordered thead:first-child tr:first-child th,
.table-bordered tbody:first-child tr:first-child th,
.table-bordered tbody:first-child tr:first-child td {
  border-top: 0; }

.table-bordered thead:first-child tr:first-child > th:first-child,
.table-bordered tbody:first-child tr:first-child > td:first-child,
.table-bordered tbody:first-child tr:first-child > th:first-child {
  -webkit-border-top-left-radius: 4px;
  border-top-left-radius: 4px;
  -moz-border-radius-topleft: 4px; }

.table-bordered thead:first-child tr:first-child > th:last-child,
.table-bordered tbody:first-child tr:first-child > td:last-child,
.table-bordered tbody:first-child tr:first-child > th:last-child {
  -webkit-border-top-right-radius: 4px;
  border-top-right-radius: 4px;
  -moz-border-radius-topright: 4px; }

.table-bordered thead:last-child tr:last-child > th:first-child,
.table-bordered tbody:last-child tr:last-child > td:first-child,
.table-bordered tbody:last-child tr:last-child > th:first-child,
.table-bordered tfoot:last-child tr:last-child > td:first-child,
.table-bordered tfoot:last-child tr:last-child > th:first-child {
  -webkit-border-bottom-left-radius: 4px;
  border-bottom-left-radius: 4px;
  -moz-border-radius-bottomleft: 4px; }

.table-bordered thead:last-child tr:last-child > th:last-child,
.table-bordered tbody:last-child tr:last-child > td:last-child,
.table-bordered tbody:last-child tr:last-child > th:last-child,
.table-bordered tfoot:last-child tr:last-child > td:last-child,
.table-bordered tfoot:last-child tr:last-child > th:last-child {
  -webkit-border-bottom-right-radius: 4px;
  border-bottom-right-radius: 4px;
  -moz-border-radius-bottomright: 4px; }

.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
  -webkit-border-bottom-left-radius: 0;
  border-bottom-left-radius: 0;
  -moz-border-radius-bottomleft: 0; }

.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
  -webkit-border-bottom-right-radius: 0;
  border-bottom-right-radius: 0;
  -moz-border-radius-bottomright: 0; }

.table-bordered caption + thead tr:first-child th:first-child,
.table-bordered caption + tbody tr:first-child td:first-child,
.table-bordered colgroup + thead tr:first-child th:first-child,
.table-bordered colgroup + tbody tr:first-child td:first-child {
  -webkit-border-top-left-radius: 4px;
  border-top-left-radius: 4px;
  -moz-border-radius-topleft: 4px; }

.table-bordered caption + thead tr:first-child th:last-child,
.table-bordered caption + tbody tr:first-child td:last-child,
.table-bordered colgroup + thead tr:first-child th:last-child,
.table-bordered colgroup + tbody tr:first-child td:last-child {
  -webkit-border-top-right-radius: 4px;
  border-top-right-radius: 4px;
  -moz-border-radius-topright: 4px; }

table.docutils th {
  background-color: #e8e8e8; }

table.docutils tr:hover {
  background-color: whitesmoke; }

.table-striped tbody > tr:nth-child(odd) > td,
.table-striped tbody > tr:nth-child(odd) > th {
  background-color: rgba(252, 248, 244, 0.75); }

.table-hover tbody tr:hover > td,
.table-hover tbody tr:hover > th {
  background-color: rgba(241, 222, 204, 0.75); }

table td[class*="span"],
table th[class*="span"],
.row-fluid table td[class*="span"],
.row-fluid table th[class*="span"] {
  display: table-cell;
  float: none;
  margin-left: 0; }

.hero-unit {
  padding: 60px;
  margin-bottom: 30px;
  font-size: 18px;
  font-weight: 200;
  line-height: 30px;
  color: inherit;
  background-color: rgba(230, 197, 164, 0.75);
  -webkit-border-radius: 6px;
  -moz-border-radius: 6px;
  border-radius: 6px; }

.hero-unit h1 {
  margin-bottom: 0;
  font-size: 60px;
  line-height: 1;
  letter-spacing: -1px;
  color: inherit; }

.hero-unit li {
  line-height: 30px; }

/* rst2html default used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
  border: 0; }

table.borderless td, table.borderless th {
  /* Override padding for "table.docutils td" with "! important".
     The right padding separates the table cells. */
  padding: 0 0.5em 0 0 !important; }

.first {
  /* Override more specific margin styles with "! important". */
  margin-top: 0 !important; }

.last, .with-subtitle {
  margin-bottom: 0 !important; }

.hidden {
  display: none; }

a.toc-backref {
  text-decoration: none;
  color: #444444; }

blockquote.epigraph {
  margin: 2em 5em; }

dl.docutils dd {
  margin-bottom: 0.5em; }

object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
  overflow: hidden; }

/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
  font-weight: bold }
*/
div.abstract {
  margin: 2em 5em; }

div.abstract p.topic-title {
  font-weight: bold;
  text-align: center; }

div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
  margin: 2em;
  border: medium outset;
  padding: 1em; }

div.note, div.warning {
  margin: 1.5em 0px;
  border: none; }

div.note p.admonition-title,
div.warning p.admonition-title {
  display: none; }

/* Clearfix
 * http://css-tricks.com/snippets/css/clear-fix/
 */
div.note:after,
div.warning:after {
  content: "";
  display: table;
  clear: both; }

div.note p:before,
div.warning p:before {
  display: block;
  float: left;
  font-size: 4em;
  line-height: 1em;
  margin-right: 20px;
  margin-left: 0em;
  margin-top: -10px;
  content: '\0270D';
  /*handwriting*/ }

div.warning p:before {
  content: '\026A0';
  /*warning*/ }

div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
  font-weight: bold;
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
  color: #b30000;
  font-weight: bold;
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }

/* Uncomment (and remove this text!) to get reduced vertical space in
   compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
  margin-bottom: 0.5em }

div.compound .compound-last, div.compound .compound-middle {
  margin-top: 0.5em }
*/
div.dedication {
  margin: 2em 5em;
  text-align: center;
  font-style: italic; }

div.dedication p.topic-title {
  font-weight: bold;
  font-style: normal; }

div.figure {
  margin-left: 2em;
  margin-right: 2em; }

div.footer, div.header {
  clear: both;
  font-size: smaller; }

div.line-block {
  display: block;
  margin-top: 1em;
  margin-bottom: 1em; }

div.line-block div.line-block {
  margin-top: 0;
  margin-bottom: 0;
  margin-left: 1.5em; }

div.sidebar {
  margin: 0 0 0.5em 1em;
  border: medium outset;
  padding: 1em;
  background-color: rgba(252, 248, 244, 0.75);
  width: 40%;
  float: right;
  clear: right; }

div.sidebar p.rubric {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-size: medium; }

div.system-messages {
  margin: 5em; }

div.system-messages h1 {
  color: #b30000; }

div.system-message {
  border: medium outset;
  padding: 1em; }

div.system-message p.system-message-title {
  color: #b30000;
  font-weight: bold; }

div.topic {
  margin: 2em; }

h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  margin-top: 0.4em; }

h1.title {
  text-align: center; }

h2.subtitle {
  text-align: center; }

hr.docutils {
  width: 75%; }

img.align-left, .figure.align-left, object.align-left {
  clear: left;
  float: left;
  margin-right: 1em; }

img.align-right, .figure.align-right, object.align-right {
  clear: right;
  float: right;
  margin-left: 1em; }

img.align-center, .figure.align-center, object.align-center {
  display: block;
  margin-left: auto;
  margin-right: auto; }

.align-left {
  text-align: left; }

.align-center {
  clear: both;
  text-align: center; }

.align-right {
  text-align: right; }

/* reset inner alignment in figures */
div.align-right {
  text-align: inherit; }

/* div.align-center * { */
/*   text-align: left } */

ul.simple > li {
  margin-bottom: 0.5em }

ol.simple, ul.simple {
  margin-bottom: 1em; }

ol.arabic {
  list-style: decimal; }

ol.loweralpha {
  list-style: lower-alpha; }

ol.upperalpha {
  list-style: upper-alpha; }

ol.lowerroman {
  list-style: lower-roman; }

ol.upperroman {
  list-style: upper-roman; }

p.attribution {
  text-align: right;
  margin-left: 50%; }

p.caption {
  font-style: italic; }

p.credits {
  font-style: italic;
  font-size: smaller; }

p.label {
  white-space: nowrap; }

p.rubric {
  font-weight: bold;
  font-size: larger;
  color: maroon;
  text-align: center; }

p.sidebar-title {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: bold;
  font-size: larger; }

p.sidebar-subtitle {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: bold; }

p.topic-title {
  font-weight: bold; }

pre.address {
  margin-bottom: 0;
  margin-top: 0;
  font: inherit; }

pre.literal-block, pre.doctest-block, pre.math, pre.code {
  margin-left: 2em;
  margin-right: 2em; }

pre.code .ln {
  color: grey; }

/* line numbers */
pre.code, code {
  background-color: #eeeeee; }

pre.code .comment, code .comment {
  color: #5c6576; }

pre.code .keyword, code .keyword {
  color: #3B0D06;
  font-weight: bold; }

pre.code .literal.string, code .literal.string {
  color: #0c5404; }

pre.code .name.builtin, code .name.builtin {
  color: #352b84; }

pre.code .deleted, code .deleted {
  background-color: #DEB0A1; }

pre.code .inserted, code .inserted {
  background-color: #A3D289; }

span.classifier {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-style: oblique; }

span.classifier-delimiter {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
  font-weight: bold; }

span.interpreted {
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; }

span.option {
  white-space: nowrap; }

span.pre {
  white-space: pre; }

span.problematic {
  color: #b30000; }

span.section-subtitle {
  /* font-size relative to parent (h1..h6 element) */
  font-size: 80%; }

table.citation {
  border-left: solid 1px #666666;
  margin-left: 1px; }

table.docinfo {
  margin: 0em;
  margin-top: 2em;
  margin-bottom: 2em;
  font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important;
  color: #444444; }

table.docutils {
  margin-top: 0.5em;
  margin-bottom: 0.5em; }

table.footnote {
  border-left: solid 1px #2d2d2d;
  margin-left: 1px; }

table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
  padding-left: 0.5em;
  padding-right: 0.5em;
  vertical-align: top; }

table.docutils th.field-name, table.docinfo th.docinfo-name {
  font-weight: 700;
  text-align: left;
  white-space: nowrap;
  padding-left: 0; }

h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  font-size: 100%; }

ul.auto-toc {
  list-style-type: none; }

span.DecNumber {
  color: #252dbe; }

span.BinNumber {
  color: #252dbe; }

span.HexNumber {
  color: #252dbe; }

span.OctNumber {
  color: #252dbe; }

span.FloatNumber {
  color: #252dbe; }

span.Identifier {
  color: #3b3b3b; }

span.Keyword {
  font-weight: 600;
  color: #5e8f60; }

span.StringLit {
  color: #a4255b; }

span.LongStringLit {
  color: #a4255b; }

span.CharLit {
  color: #a4255b; }

span.EscapeSequence {
  color: black; }

span.Operator {
  color: black; }

span.Punctuation {
  color: black; }

span.Comment, span.LongComment {
  font-style: italic;
  font-weight: 400;
  color: #484a86; }

span.RegularExpression {
  color: darkviolet; }

span.TagStart {
  color: darkviolet; }

span.TagEnd {
  color: darkviolet; }

span.Key {
  color: #252dbe; }

span.Value {
  color: #252dbe; }

span.RawData {
  color: #a4255b; }

span.Assembler {
  color: #252dbe; }

span.Preprocessor {
  color: #252dbe; }

span.Directive {
  color: #252dbe; }

span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
span.Other {
  color: black; }

/* Pop type, const, proc, and iterator defs in nim def blocks */
dt pre > span.Identifier, dt pre > span.Operator {
  color: #155da4;
  font-weight: 700; }

dt pre > span.Identifier ~ span.Identifier, dt pre > span.Operator ~ span.Identifier {
  color: inherit;
  font-weight: inherit; }

dt pre > span.Operator ~ span.Identifier {
  color: inherit;
  font-weight: inherit; }

/* Nim sprite for the footer (taken from main page favicon) */
.nim-sprite {
  display: inline-block;
  height: 12px;
  width: 12px;
  background-position: 0 0;
  background-size: 12px 12px;
  -webkit-filter: opacity(50%);
  background-repeat: no-repeat;
  background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
  margin-bottom: -5px; }

div.search_results {
  background-color: antiquewhite;
  margin: 3em;
  padding: 1em;
  border: 1px solid #4d4d4d;
}

div#global-links ul {
  margin-left: 0;
  list-style-type: none;
}

span.pragmadots {
  /* Position: relative frees us up to make the dots
  look really nice without fucking up the layout and
  causing bulging in the parent container */
  position: relative;
  /* 1px down looks slightly nicer */
  top: 1px;

  padding: 2px;
  background-color: #D3D3D3;
  border-radius: 4px;
  margin: 0 2px;
  cursor: pointer;

  /* For some reason on Chrome, making the font size
  smaller than 1em is causing the parent container to
  bulge slightly. So, we're stuck with inheriting 1em,
  which is sad, because 0.8em looks better... */
}
span.pragmadots:hover {
  background-color: #DBDBDB;
}
span.pragmawrap {
  display: none;
}

</style>

<script type="text/javascript" src="dochack.js"></script>

<script type="text/javascript">
function main() {
  var pragmaDots = document.getElementsByClassName("pragmadots");
  for (var i = 0; i < pragmaDots.length; i++) {
    pragmaDots[i].onclick = function(event) {
      // Hide tease
      event.target.parentNode.style.display = "none";
      // Show actual
      event.target.parentNode.nextElementSibling.style.display = "inline";
    }
  }
}
</script>

</head>
<body onload="main()">
<div class="document" id="documentId">
  <div class="container">
    <h1 class="title">audio</h1>
    <div class="row">
  <div class="three columns">
  <div id="global-links">
    <ul class="simple">
    </ul>
  </div>
  <div id="searchInputDiv">
    Search: <input type="text" id="searchInput"
      onkeyup="search()" />
  </div>
  <div>
    Group by:
    <select onchange="groupBy(this.value)">
      <option value="section">Section</option>
      <option value="type">Type</option>
    </select>
  </div>
  <ul class="simple simple-toc" id="toc-list">
<li>
  <a class="reference reference-toplevel" href="#6" id="56">Imports</a>
  <ul class="simple simple-toc-section">
    
  </ul>
</li>
<li>
  <a class="reference reference-toplevel" href="#7" id="57">Types</a>
  <ul class="simple simple-toc-section">
      <li><a class="reference" href="#Channel"
    title="Channel = int"><wbr />Channel<span class="attachedType" style="visibility:hidden"></span></a></li>
  <li><a class="reference" href="#Distance"
    title="Distance = range[0 .. 255]"><wbr />Distance<span class="attachedType" style="visibility:hidden"></span></a></li>
  <li><a class="reference" href="#Panning"
    title="Panning = range[0 .. 255]"><wbr />Panning<span class="attachedType" style="visibility:hidden"></span></a></li>
  <li><a class="reference" href="#Volume"
    title="Volume = range[0 .. mix.MaxVolume]"><wbr />Volume<span class="attachedType" style="visibility:hidden"></span></a></li>
  <li><a class="reference" href="#Sound"
    title="Sound = ref object of RootObj
  fChunk: mix.Chunk
  fChannel: Channel"><wbr />Sound<span class="attachedType" style="visibility:hidden"></span></a></li>
  <li><a class="reference" href="#Music"
    title="Music = ref object of RootObj
  fMusic: mix.Music"><wbr />Music<span class="attachedType" style="visibility:hidden"></span></a></li>
  <li><a class="reference" href="#Playlist"
    title="Playlist = ref object of RootObj
  list*: seq[Music]
  fIndex: int
  fFinished: bool"><wbr />Playlist<span class="attachedType" style="visibility:hidden"></span></a></li>

  </ul>
</li>
<li>
  <a class="reference reference-toplevel" href="#8" id="58">Vars</a>
  <ul class="simple simple-toc-section">
      <li><a class="reference" href="#pl
Download .txt
gitextract_oovdsi4y/

├── LICENSE
├── README.md
├── STYLE.md
├── demos/
│   ├── README.md
│   ├── assets/
│   │   ├── csv/
│   │   │   ├── atlas.csv
│   │   │   ├── map0.csv
│   │   │   └── map_camera_test.csv
│   │   └── mus/
│   │       ├── absolu.mod
│   │       ├── biotech.xm
│   │       ├── cancan.mod
│   │       └── cornered!.xm
│   ├── demo1/
│   │   ├── README.md
│   │   ├── demo1.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo10/
│   │   ├── README.md
│   │   ├── demo10.nim
│   │   ├── earth.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo11/
│   │   ├── README.md
│   │   ├── demo11.nim
│   │   ├── earth.nim
│   │   └── mainscene.nim
│   ├── demo12/
│   │   ├── README.md
│   │   ├── demo12.nim
│   │   └── mainscene.nim
│   ├── demo13/
│   │   ├── README.md
│   │   ├── cursor.nim
│   │   ├── demo13.nim
│   │   └── mainscene.nim
│   ├── demo14/
│   │   ├── README.md
│   │   ├── demo14.nim
│   │   ├── dwarf.nim
│   │   └── mainscene.nim
│   ├── demo15/
│   │   ├── README.md
│   │   ├── demo15.nim
│   │   └── mainscene.nim
│   ├── demo16/
│   │   ├── README.md
│   │   ├── demo16.nim
│   │   └── mainscene.nim
│   ├── demo17/
│   │   ├── README.md
│   │   ├── btnCircle.nim
│   │   ├── btnSquare.nim
│   │   ├── demo17.nim
│   │   └── mainscene.nim
│   ├── demo18/
│   │   ├── README.md
│   │   ├── demo18.nim
│   │   └── mainscene.nim
│   ├── demo19/
│   │   ├── README.md
│   │   ├── demo19.nim
│   │   └── mainscene.nim
│   ├── demo2/
│   │   ├── README.md
│   │   ├── demo2.nim
│   │   ├── earth.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo20/
│   │   ├── README.md
│   │   ├── demo20.nim
│   │   └── mainscene.nim
│   ├── demo21/
│   │   ├── README.md
│   │   ├── demo21.nim
│   │   ├── joypoint.nim
│   │   └── mainscene.nim
│   ├── demo22/
│   │   ├── README.md
│   │   ├── demo22.nim
│   │   ├── mainscene.nim
│   │   └── video.mpg
│   ├── demo23/
│   │   ├── README.md
│   │   ├── demo23.nim
│   │   ├── mainscene.nim
│   │   └── private/
│   │       ├── border_fill_graphic.nim
│   │       ├── circle_graphic.nim
│   │       └── frame.nim
│   ├── demo3/
│   │   ├── README.md
│   │   ├── demo3.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo4/
│   │   ├── README.md
│   │   ├── demo4.nim
│   │   ├── dwarf.nim
│   │   └── mainscene.nim
│   ├── demo5/
│   │   ├── README.md
│   │   ├── cursor.nim
│   │   ├── demo5.nim
│   │   ├── earth.nim
│   │   ├── line.nim
│   │   ├── mainscene.nim
│   │   ├── poly1.nim
│   │   ├── poly2.nim
│   │   ├── poly3.nim
│   │   ├── poly9.nim
│   │   └── spaceman.nim
│   ├── demo6/
│   │   ├── README.md
│   │   ├── demo6.nim
│   │   ├── earth.nim
│   │   ├── mainscene.nim
│   │   └── spaceman.nim
│   ├── demo7/
│   │   ├── README.md
│   │   ├── demo7.nim
│   │   ├── earth.nim
│   │   └── mainscene.nim
│   ├── demo8/
│   │   ├── README.md
│   │   ├── demo8.nim
│   │   └── mainscene.nim
│   ├── demo9/
│   │   ├── README.md
│   │   ├── demo9.nim
│   │   └── mainscene.nim
│   └── nim.cfg
├── docs/
│   ├── changelog.html
│   ├── demos.html
│   ├── docs/
│   │   ├── assets.html
│   │   ├── audio.html
│   │   ├── bitmapfont.html
│   │   ├── count.html
│   │   ├── draw.html
│   │   ├── emitter.html
│   │   ├── entity.html
│   │   ├── font.html
│   │   ├── graphic.html
│   │   ├── gui/
│   │   │   ├── button.html
│   │   │   ├── progressbar.html
│   │   │   ├── radio.html
│   │   │   ├── textinput.html
│   │   │   └── widget.html
│   │   ├── indexedimage.html
│   │   ├── input.html
│   │   ├── mosaic.html
│   │   ├── nimgame.html
│   │   ├── perspectiveimage.html
│   │   ├── plugin/
│   │   │   ├── mpeggraphic.html
│   │   │   ├── tar.html
│   │   │   └── zzip.html
│   │   ├── private/
│   │   │   └── collider.html
│   │   ├── procgraphic.html
│   │   ├── scene.html
│   │   ├── settings.html
│   │   ├── textfield.html
│   │   ├── textgraphic.html
│   │   ├── textureatlas.html
│   │   ├── texturegraphic.html
│   │   ├── tilemap.html
│   │   ├── truetypefont.html
│   │   ├── tween.html
│   │   ├── types.html
│   │   ├── typewriter.html
│   │   └── utils.html
│   ├── docs.html
│   ├── index.html
│   ├── links.html
│   ├── snippets.html
│   ├── structure.js
│   ├── style.css
│   ├── template.html
│   ├── template_tutorial.html
│   ├── tut101_bounce.html
│   ├── tut102_platformer.html
│   └── tutorials.html
├── nimgame2/
│   ├── assets.nim
│   ├── audio.nim
│   ├── bitmapfont.nim
│   ├── draw.nim
│   ├── emitter.nim
│   ├── entity.nim
│   ├── font.nim
│   ├── graphic.nim
│   ├── gui/
│   │   ├── button.nim
│   │   ├── progressbar.nim
│   │   ├── radio.nim
│   │   ├── textinput.nim
│   │   └── widget.nim
│   ├── indexedimage.nim
│   ├── input.nim
│   ├── mosaic.nim
│   ├── nimgame.nim
│   ├── perspectiveimage.nim
│   ├── plugin/
│   │   ├── mpeggraphic.nim
│   │   ├── tar.nim
│   │   └── zzip.nim
│   ├── private/
│   │   └── collider.nim
│   ├── procgraphic.nim
│   ├── scene.nim
│   ├── settings.nim
│   ├── textfield.nim
│   ├── textgraphic.nim
│   ├── textureatlas.nim
│   ├── texturegraphic.nim
│   ├── tilemap.nim
│   ├── truetypefont.nim
│   ├── tween.nim
│   ├── types.nim
│   ├── typewriter.nim
│   └── utils.nim
├── nimgame2.nim
└── nimgame2.nimble
Download .txt
SYMBOL INDEX (12 symbols across 1 files)

FILE: docs/structure.js
  function createFavicon (line 7) | function createFavicon() {
  function headerLink (line 25) | function headerLink(name, disabled) {
  function createHeader (line 45) | function createHeader(title, logo) {
  function createFooter (line 96) | function createFooter() {
  function createClassList (line 110) | function createClassList(cname) {
  function createSnippetsList (line 149) | function createSnippetsList() {
  function createSectionsList (line 153) | function createSectionsList() {
  function listLink (line 210) | function listLink(dir, link) {
  function fillListColumn (line 228) | function fillListColumn(obj, from, to) {
  function createDocsLinks (line 246) | function createDocsLinks() {
  function rankName (line 259) | function rankName(level) {
  function createRanks (line 268) | function createRanks() {
Condensed preview — 195 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,104K chars).
[
  {
    "path": "LICENSE",
    "chars": 1174,
    "preview": "# nimgame2\n# Copyright (c) 2016-2020 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of charge, to an"
  },
  {
    "path": "README.md",
    "chars": 4084,
    "preview": "Nimgame 2\n=========\n\nA simple 2D game engine for Nim language.\n\nFor more information check [home page](https://vladar4.g"
  },
  {
    "path": "STYLE.md",
    "chars": 2943,
    "preview": "Nimgame 2 code formatting style\n===============================\n\nIn general, follow [NEP1](https://nim-lang.org/docs/nep"
  },
  {
    "path": "demos/README.md",
    "chars": 724,
    "preview": "Nimgame 2 Demos\n===============\n\n* [demo1](demo1) Performance\n\n* [demo2](demo2) Graphic\n\n* [demo3](demo3) Input\n\n* [demo"
  },
  {
    "path": "demos/assets/csv/atlas.csv",
    "chars": 96,
    "preview": "spaceman, 12, 33, 42, 66\ngradient, 65, 9, 16, 90\nbutton, 82, 26, 48, 72\nsprite, 132, 0, 68, 100\n"
  },
  {
    "path": "demos/assets/csv/map0.csv",
    "chars": 1040,
    "preview": "0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3\n3,3,3,1,1,1,3,1,1,1,1,1,3,1,1,1,1,1,1,1,1,3,1,1,1,3\n3,1,1,1,1,1,1,1,"
  },
  {
    "path": "demos/assets/csv/map_camera_test.csv",
    "chars": 9800,
    "preview": "1,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,"
  },
  {
    "path": "demos/demo1/README.md",
    "chars": 82,
    "preview": "Nimgame 2: Demo 1\n=================\n\nPerformance demo.\n\n![Screenshot](demo1.png)\n\n"
  },
  {
    "path": "demos/demo1/demo1.nim",
    "chars": 215,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo1/mainscene.nim",
    "chars": 1899,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/scene,\n  nimgame2/s"
  },
  {
    "path": "demos/demo1/spaceman.nim",
    "chars": 741,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/graphic,\n  nimgame2/scene,\n  nimgame2/types,\n  nimgame2/utils\n\n"
  },
  {
    "path": "demos/demo10/README.md",
    "chars": 110,
    "preview": "Nimgame 2: Demo 10\n==================\n\nLayers demo. Demonstrates entity layering.\n\n![Screenshot](demo10.png)\n\n"
  },
  {
    "path": "demos/demo10/demo10.nim",
    "chars": 211,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo10/earth.nim",
    "chars": 246,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Earth* = ref object of Entity\n\n\nproc init*(entity: Earth) =\n  entit"
  },
  {
    "path": "demos/demo10/mainscene.nim",
    "chars": 1405,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  ni"
  },
  {
    "path": "demos/demo10/spaceman.nim",
    "chars": 261,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Spaceman* = ref object of Entity\n\n\nproc init*(entity: Spaceman) =\n "
  },
  {
    "path": "demos/demo11/README.md",
    "chars": 114,
    "preview": "Nimgame 2: Demo 11\n==================\n\nTweens demo. Demonstrates tweening procedures.\n\n![Screenshot](demo11.png)\n\n"
  },
  {
    "path": "demos/demo11/demo11.nim",
    "chars": 213,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 1280, h = 720, title = \"N"
  },
  {
    "path": "demos/demo11/earth.nim",
    "chars": 263,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/types\n\ntype\n  Earth* = ref object of Entity\n\n\nproc init*(entity"
  },
  {
    "path": "demos/demo11/mainscene.nim",
    "chars": 4140,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/bitmapfont,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/textgraphic,\n  nimgame2"
  },
  {
    "path": "demos/demo12/README.md",
    "chars": 118,
    "preview": "Nimgame 2: Demo 12\n==================\n\nEmitter demo. Demonstrates particle emitter usage.\n\n![Screenshot](demo12.png)\n\n"
  },
  {
    "path": "demos/demo12/demo12.nim",
    "chars": 212,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo12/mainscene.nim",
    "chars": 3530,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/emitter,\n  nimgame2/texturegraphic,\n  nimgame2"
  },
  {
    "path": "demos/demo13/README.md",
    "chars": 281,
    "preview": "Nimgame 2: Demo 13\n==================\n\nTileMap demo. Demonstrates tile maps usage.\n\nNote\n----\nFor the performance purpos"
  },
  {
    "path": "demos/demo13/cursor.nim",
    "chars": 842,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/input,\n  nimgame2/tilemap\n\ntype\n  Cursor* = ref object of Entit"
  },
  {
    "path": "demos/demo13/demo13.nim",
    "chars": 212,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo13/mainscene.nim",
    "chars": 2716,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/tilemap,\n  nimgame2"
  },
  {
    "path": "demos/demo14/README.md",
    "chars": 190,
    "preview": "Nimgame 2: Demo 14\n==================\n\nSecond TileMap demo. Demonstrates practical TileMap usage, along with Tween an Em"
  },
  {
    "path": "demos/demo14/demo14.nim",
    "chars": 214,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo14/dwarf.nim",
    "chars": 2374,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/tilemap,\n  nimgame2/tween,\n  nimgame"
  },
  {
    "path": "demos/demo14/mainscene.nim",
    "chars": 2847,
    "preview": "import\n  parseutils,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/emitter,\n  nimgame2/entity,\n  nimgame2/texturegraph"
  },
  {
    "path": "demos/demo15/README.md",
    "chars": 164,
    "preview": "Nimgame 2: Demo 15\n==================\n\nCamera demo. Demonstrates camera usage.\n\nNote a negative sign in front of the cam"
  },
  {
    "path": "demos/demo15/demo15.nim",
    "chars": 211,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo15/mainscene.nim",
    "chars": 2933,
    "preview": "import\n  parseutils,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/tilem"
  },
  {
    "path": "demos/demo16/README.md",
    "chars": 112,
    "preview": "Nimgame 2: Demo 16\n==================\n\nParallax demo. Demonstrates parallax effect.\n\n![Screenshot](demo16.png)\n\n"
  },
  {
    "path": "demos/demo16/demo16.nim",
    "chars": 213,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo16/mainscene.nim",
    "chars": 2013,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  nimgame2/scene,\n  nimgame2/"
  },
  {
    "path": "demos/demo17/README.md",
    "chars": 126,
    "preview": "Nimgame 2: Demo 17\n==================\n\nFirst GUI demo. Demonstrates buttons and text field usage.\n\n![Screenshot](demo17."
  },
  {
    "path": "demos/demo17/btnCircle.nim",
    "chars": 466,
    "preview": "import\n  nimgame2/graphic,\n  nimgame2/input,\n  nimgame2/gui/widget,\n  nimgame2/gui/button\n\n\ntype\n  CircleButton* = ref o"
  },
  {
    "path": "demos/demo17/btnSquare.nim",
    "chars": 439,
    "preview": "import\n  nimgame2/graphic,\n  nimgame2/input,\n  nimgame2/gui/button\n\n\ntype\n  SquareButton* = ref object of GuiButton\n\n\npr"
  },
  {
    "path": "demos/demo17/demo17.nim",
    "chars": 208,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo17/mainscene.nim",
    "chars": 3955,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  nimgame2/m"
  },
  {
    "path": "demos/demo18/README.md",
    "chars": 130,
    "preview": "Nimgame 2: Demo 18\n==================\n\nIndexedImage. Demonstrates palette swapping in indexed images.\n\n![Screenshot](dem"
  },
  {
    "path": "demos/demo18/demo18.nim",
    "chars": 248,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 320, h = 240, title = \"Ni"
  },
  {
    "path": "demos/demo18/mainscene.nim",
    "chars": 3527,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  nimgame2/i"
  },
  {
    "path": "demos/demo19/README.md",
    "chars": 127,
    "preview": "Nimgame 2: Demo 19\n==================\n\nPerspectiveImage. Demonstrates perspective transformations.\n\n![Screenshot](demo19"
  },
  {
    "path": "demos/demo19/demo19.nim",
    "chars": 221,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo19/mainscene.nim",
    "chars": 3060,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  nimgame2/perspectiveimage,\n"
  },
  {
    "path": "demos/demo2/README.md",
    "chars": 148,
    "preview": "Nimgame 2: Demo 2\n=================\n\nGraphic demo.\n\nDemonstrates color and alpha modifiers, blending modes, and scaling."
  },
  {
    "path": "demos/demo2/demo2.nim",
    "chars": 242,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo2/earth.nim",
    "chars": 246,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Earth* = ref object of Entity\n\n\nproc init*(entity: Earth) =\n  entit"
  },
  {
    "path": "demos/demo2/mainscene.nim",
    "chars": 4394,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  ni"
  },
  {
    "path": "demos/demo2/spaceman.nim",
    "chars": 261,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Spaceman* = ref object of Entity\n\n\nproc init*(entity: Spaceman) =\n "
  },
  {
    "path": "demos/demo20/README.md",
    "chars": 128,
    "preview": "Nimgame 2: Demo 20\n==================\n\nTextureAtlas. Demonstrates texture atlas loading and access.\n\n![Screenshot](demo2"
  },
  {
    "path": "demos/demo20/demo20.nim",
    "chars": 248,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 320, h = 240, title = \"Ni"
  },
  {
    "path": "demos/demo20/mainscene.nim",
    "chars": 1436,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/gui/button,\n  nimgame2/texturegraphic,\n  nimgame2/textureatlas,"
  },
  {
    "path": "demos/demo21/README.md",
    "chars": 116,
    "preview": "Nimgame 2: Demo 21\n==================\n\nJoysticks. Demonstrates joystick input handling.\n\n![Screenshot](demo21.png)\n\n"
  },
  {
    "path": "demos/demo21/demo21.nim",
    "chars": 214,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo21/joypoint.nim",
    "chars": 1203,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/textgraphic,\n  nimgame2/texturegraphic,\n  nimgame2/font,\n  nimg"
  },
  {
    "path": "demos/demo21/mainscene.nim",
    "chars": 1216,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  nimgame2/s"
  },
  {
    "path": "demos/demo22/README.md",
    "chars": 85,
    "preview": "Nimgame 2: Demo 22\n==================\n\nMpegGraphic demo.\n\n![Screenshot](demo22.png)\n\n"
  },
  {
    "path": "demos/demo22/demo22.nim",
    "chars": 247,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo22/mainscene.nim",
    "chars": 2645,
    "preview": "import\n  strutils,\n  nimgame2/plugin/mpeggraphic,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/inp"
  },
  {
    "path": "demos/demo23/README.md",
    "chars": 126,
    "preview": "Nimgame 2: Demo 23\n==================\n\nTransform demo by [CodeDoes](https://github.com/CodeDoes).\n\n![Screenshot](demo23."
  },
  {
    "path": "demos/demo23/demo23.nim",
    "chars": 242,
    "preview": "import\n  nimgame2 / [\n    nimgame, settings\n  ],\n  mainscene\n\n\ngame = newGame()\nif game.init(640, 480, \"Nimgame 2: Demo "
  },
  {
    "path": "demos/demo23/mainscene.nim",
    "chars": 2575,
    "preview": "import\n  nimgame2 / [\n    truetypefont, textgraphic, entity,\n    nimgame, scene, types,\n    graphic, input, settings],\n "
  },
  {
    "path": "demos/demo23/private/border_fill_graphic.nim",
    "chars": 996,
    "preview": "import\n  nimgame2 / [\n    types, graphic, types\n  ]\n\n\ntype\n  BorderFillGraphic* = ref object of Graphic\n    border_color"
  },
  {
    "path": "demos/demo23/private/circle_graphic.nim",
    "chars": 1290,
    "preview": "import\n  nimgame2 / [\n    types, graphic, draw, utils\n  ],\n  border_fill_graphic\n\n\ntype\n  CircleGraphic* = ref object of"
  },
  {
    "path": "demos/demo23/private/frame.nim",
    "chars": 2052,
    "preview": "import \n  nimgame2 / [\n    types, graphic, draw, utils\n  ],\n  border_fill_graphic\n\ntype\n  FrameGraphic* = ref object of "
  },
  {
    "path": "demos/demo3/README.md",
    "chars": 115,
    "preview": "Nimgame 2: Demo 3\n=================\n\nInput demo. Demonstrates keyboard and mouse input.\n\n![Screenshot](demo3.png)\n\n"
  },
  {
    "path": "demos/demo3/demo3.nim",
    "chars": 219,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo3/mainscene.nim",
    "chars": 3265,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  nimgame2/s"
  },
  {
    "path": "demos/demo3/spaceman.nim",
    "chars": 338,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Spaceman* = ref object of Entity\n\n\nproc init*(entity: Spaceman) =\n "
  },
  {
    "path": "demos/demo4/README.md",
    "chars": 108,
    "preview": "Nimgame 2: Demo 4\n=================\n\nSprite demo. Demonstrates sprite animation.\n\n![Screenshot](demo4.png)\n\n"
  },
  {
    "path": "demos/demo4/demo4.nim",
    "chars": 222,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo4/dwarf.nim",
    "chars": 255,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Dwarf* = ref object of Entity\n\n\nproc init*(entity: Dwarf) =\n  entit"
  },
  {
    "path": "demos/demo4/mainscene.nim",
    "chars": 2392,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  ni"
  },
  {
    "path": "demos/demo5/README.md",
    "chars": 114,
    "preview": "Nimgame 2: Demo 5\n=================\n\nColliders demo. Demonstrates different colliders.\n\n![Screenshot](demo5.png)\n\n"
  },
  {
    "path": "demos/demo5/cursor.nim",
    "chars": 595,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity,\n  nimgame2/input\n\ntype\n  Cursor* = ref object of Entity\n    collidedWith*:"
  },
  {
    "path": "demos/demo5/demo5.nim",
    "chars": 314,
    "preview": "import\n  sdl2_nim/sdl,\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = "
  },
  {
    "path": "demos/demo5/earth.nim",
    "chars": 547,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Earth* = ref object of Entity\n    collidedWith*: seq[string]\n\n\nproc"
  },
  {
    "path": "demos/demo5/line.nim",
    "chars": 511,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Line* = ref object of Entity\n    collidedWith*: seq[string]\n\n\nproc "
  },
  {
    "path": "demos/demo5/mainscene.nim",
    "chars": 4286,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  ni"
  },
  {
    "path": "demos/demo5/poly1.nim",
    "chars": 595,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Poly1* = ref object of Entity\n    collidedWith*: seq[string]\n\n\nproc"
  },
  {
    "path": "demos/demo5/poly2.nim",
    "chars": 615,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Poly2* = ref object of Entity\n    collidedWith*: seq[string]\n\n\nproc"
  },
  {
    "path": "demos/demo5/poly3.nim",
    "chars": 636,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Poly3* = ref object of Entity\n    collidedWith*: seq[string]\n\n\nproc"
  },
  {
    "path": "demos/demo5/poly9.nim",
    "chars": 791,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Poly9* = ref object of Entity\n    collidedWith*: seq[string]\n\n\nproc"
  },
  {
    "path": "demos/demo5/spaceman.nim",
    "chars": 573,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Spaceman* = ref object of Entity\n    collidedWith*: seq[string]\n\n\np"
  },
  {
    "path": "demos/demo6/README.md",
    "chars": 129,
    "preview": "Nimgame 2: Demo 6\n=================\n\nGrouping demo. Demonstrates effects of setting up entity parent.\n\n![Screenshot](dem"
  },
  {
    "path": "demos/demo6/demo6.nim",
    "chars": 243,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo6/earth.nim",
    "chars": 258,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Earth* = ref object of Entity\n\n\nproc init*(entity: Earth) =\n  entit"
  },
  {
    "path": "demos/demo6/mainscene.nim",
    "chars": 2109,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/texturegraphic,\n  nimgame2/input,\n  ni"
  },
  {
    "path": "demos/demo6/spaceman.nim",
    "chars": 358,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Spaceman* = ref object of Entity\n\n\nproc init*(entity: Spaceman) =\n "
  },
  {
    "path": "demos/demo7/README.md",
    "chars": 115,
    "preview": "Nimgame 2: Demo 7\n=================\n\nText demo. Demonstrates bitmap and TrueType fonts.\n\n![Screenshot](demo7.png)\n\n"
  },
  {
    "path": "demos/demo7/demo7.nim",
    "chars": 239,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo7/earth.nim",
    "chars": 255,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/entity\n\ntype\n  Earth* = ref object of Entity\n\n\nproc init*(entity: Earth) =\n  entit"
  },
  {
    "path": "demos/demo7/mainscene.nim",
    "chars": 4313,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/font,\n  nimgame2/bitmapfont,\n  nimgame2/truetypefont,\n  nimgame2/draw,\n  n"
  },
  {
    "path": "demos/demo8/README.md",
    "chars": 116,
    "preview": "Nimgame 2: Demo 8\n=================\n\nProcGraphic demo. Demonstrates procedural graphics.\n\n![Screenshot](demo8.png)\n\n"
  },
  {
    "path": "demos/demo8/demo8.nim",
    "chars": 246,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  mainscene\n\ngame = newGame()\nif game.init(w = 640, h = 480, title = \"Ni"
  },
  {
    "path": "demos/demo8/mainscene.nim",
    "chars": 2633,
    "preview": "import\n  math,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/entity,\n  nimgame2/graphic,\n  nimgame2/input,\n  nimgame2/"
  },
  {
    "path": "demos/demo9/README.md",
    "chars": 104,
    "preview": "Nimgame 2: Demo 9\n=================\n\nAudio demo. Demonstrates sound effects.\n\n![Screenshot](demo9.png)\n\n"
  },
  {
    "path": "demos/demo9/demo9.nim",
    "chars": 286,
    "preview": "import\n  nimgame2/nimgame,\n  nimgame2/settings,\n  nimgame2/assets,\n  nimgame2/texturegraphic,\n  mainscene\n\ngame = newGam"
  },
  {
    "path": "demos/demo9/mainscene.nim",
    "chars": 1703,
    "preview": "import\n  math,\n  nimgame2/assets,\n  nimgame2/audio,\n  nimgame2/nimgame,\n  nimgame2/draw,\n  nimgame2/input,\n  nimgame2/sc"
  },
  {
    "path": "demos/nim.cfg",
    "chars": 18,
    "preview": "--multimethods:on\n"
  },
  {
    "path": "docs/changelog.html",
    "chars": 3187,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/demos.html",
    "chars": 6453,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/docs/assets.html",
    "chars": 34030,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/audio.html",
    "chars": 98581,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/bitmapfont.html",
    "chars": 51563,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/count.html",
    "chars": 36469,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/draw.html",
    "chars": 64651,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/emitter.html",
    "chars": 35932,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/entity.html",
    "chars": 208089,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/font.html",
    "chars": 44315,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/graphic.html",
    "chars": 39091,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/gui/button.html",
    "chars": 41095,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/gui/progressbar.html",
    "chars": 43628,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/gui/radio.html",
    "chars": 44144,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/gui/textinput.html",
    "chars": 47115,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/gui/widget.html",
    "chars": 58947,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/indexedimage.html",
    "chars": 53206,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/input.html",
    "chars": 117519,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/mosaic.html",
    "chars": 58697,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/nimgame.html",
    "chars": 76164,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/perspectiveimage.html",
    "chars": 45838,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/plugin/mpeggraphic.html",
    "chars": 73468,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/plugin/tar.html",
    "chars": 44082,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/plugin/zzip.html",
    "chars": 38180,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/private/collider.html",
    "chars": 88735,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/procgraphic.html",
    "chars": 46578,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/scene.html",
    "chars": 63685,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/settings.html",
    "chars": 33825,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/textfield.html",
    "chars": 50264,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/textgraphic.html",
    "chars": 50455,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/textureatlas.html",
    "chars": 37298,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/texturegraphic.html",
    "chars": 72541,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/tilemap.html",
    "chars": 92813,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/truetypefont.html",
    "chars": 45645,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/tween.html",
    "chars": 124137,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/types.html",
    "chars": 229602,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/typewriter.html",
    "chars": 41978,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs/utils.html",
    "chars": 94895,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n  \"http://www.w3."
  },
  {
    "path": "docs/docs.html",
    "chars": 648,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/index.html",
    "chars": 7229,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/links.html",
    "chars": 2857,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/snippets.html",
    "chars": 16625,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/structure.js",
    "chars": 7361,
    "preview": "// STRUCTURE\n\n\n/**\n *  Create favicon link tag.\n */\nfunction createFavicon() {\n    var icon = document.createElement('li"
  },
  {
    "path": "docs/style.css",
    "chars": 3668,
    "preview": "/* REFERENCE\n--min-width: 20rem;\n--max-width: 40rem;\n--border-color: #999;\n*/\n\nbody {\n    padding-left: 0;\n    padding-r"
  },
  {
    "path": "docs/template.html",
    "chars": 429,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/template_tutorial.html",
    "chars": 858,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/tut101_bounce.html",
    "chars": 23310,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/tut102_platformer.html",
    "chars": 27253,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "docs/tutorials.html",
    "chars": 1424,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n\n    <title>Nimgame 2</title>\n\n    <link rel=\"styles"
  },
  {
    "path": "nimgame2/assets.nim",
    "chars": 3218,
    "preview": "# nimgame2/assets.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of ch"
  },
  {
    "path": "nimgame2/audio.nim",
    "chars": 12031,
    "preview": "# nimgame2/audio.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "nimgame2/bitmapfont.nim",
    "chars": 6239,
    "preview": "# nimgame2/bitmapfont.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free o"
  },
  {
    "path": "nimgame2/draw.nim",
    "chars": 9758,
    "preview": "# nimgame2/draw.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of char"
  },
  {
    "path": "nimgame2/emitter.nim",
    "chars": 5326,
    "preview": "# nimgame2/emitter.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of c"
  },
  {
    "path": "nimgame2/entity.nim",
    "chars": 25132,
    "preview": "# nimgame2/entity.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of ch"
  },
  {
    "path": "nimgame2/font.nim",
    "chars": 4276,
    "preview": "# nimgame2/font.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of char"
  },
  {
    "path": "nimgame2/graphic.nim",
    "chars": 1908,
    "preview": "# nimgame2/graphic.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of c"
  },
  {
    "path": "nimgame2/gui/button.nim",
    "chars": 3824,
    "preview": "# nimgame2/button.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of ch"
  },
  {
    "path": "nimgame2/gui/progressbar.nim",
    "chars": 6271,
    "preview": "# nimgame2/gui/progressbar.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, f"
  },
  {
    "path": "nimgame2/gui/radio.nim",
    "chars": 3316,
    "preview": "# nimgame2/radiogroup.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free o"
  },
  {
    "path": "nimgame2/gui/textinput.nim",
    "chars": 4435,
    "preview": "# nimgame2/textinput.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of"
  },
  {
    "path": "nimgame2/gui/widget.nim",
    "chars": 6064,
    "preview": "# nimgame2/gui/widget.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free o"
  },
  {
    "path": "nimgame2/indexedimage.nim",
    "chars": 5431,
    "preview": "# nimgame2/indexedimage.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free"
  },
  {
    "path": "nimgame2/input.nim",
    "chars": 23965,
    "preview": "# nimgame2/input.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "nimgame2/mosaic.nim",
    "chars": 8106,
    "preview": "# nimgame2/mosaic.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of ch"
  },
  {
    "path": "nimgame2/nimgame.nim",
    "chars": 12424,
    "preview": "# nimgame2/nimgame.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of c"
  },
  {
    "path": "nimgame2/perspectiveimage.nim",
    "chars": 6158,
    "preview": "# nimgame2/perspectiveimage.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, "
  },
  {
    "path": "nimgame2/plugin/mpeggraphic.nim",
    "chars": 7260,
    "preview": "# nimgame2/mpeggraphic.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free "
  },
  {
    "path": "nimgame2/plugin/tar.nim",
    "chars": 6844,
    "preview": "#\n#  dxTarRead - 0.91 - public domain\n#  no warrenty implied; use at your own risk.\n#  authored from 2017 by Dmitry Hrab"
  },
  {
    "path": "nimgame2/plugin/zzip.nim",
    "chars": 2033,
    "preview": "#\n#    Copyright (c) 2001 Guido Draheim <guidod@gmx.de>\n#    Use freely under the restrictions of the ZLIB License\n#\n\n##"
  },
  {
    "path": "nimgame2/private/collider.nim",
    "chars": 21266,
    "preview": "# nimgame2/collider.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of "
  },
  {
    "path": "nimgame2/procgraphic.nim",
    "chars": 3231,
    "preview": "# nimgame2/procgraphic.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free "
  },
  {
    "path": "nimgame2/scene.nim",
    "chars": 6908,
    "preview": "# nimgame2/scene.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "nimgame2/settings.nim",
    "chars": 1816,
    "preview": "# nimgame2/settings.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of "
  },
  {
    "path": "nimgame2/textfield.nim",
    "chars": 4458,
    "preview": "# nimgame2/gui/textfield.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, fre"
  },
  {
    "path": "nimgame2/textgraphic.nim",
    "chars": 4251,
    "preview": "# nimgame2/textgraphic.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free "
  },
  {
    "path": "nimgame2/textureatlas.nim",
    "chars": 4168,
    "preview": "# nimgame2/textureatlas.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free"
  },
  {
    "path": "nimgame2/texturegraphic.nim",
    "chars": 11453,
    "preview": "# nimgame2/texturegraphic.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, fr"
  },
  {
    "path": "nimgame2/tilemap.nim",
    "chars": 12850,
    "preview": "# nimgame2/tilemap.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of c"
  },
  {
    "path": "nimgame2/truetypefont.nim",
    "chars": 3729,
    "preview": "# nimgame2/truetypefont.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free"
  },
  {
    "path": "nimgame2/tween.nim",
    "chars": 22982,
    "preview": "# nimgame2/tween.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "nimgame2/types.nim",
    "chars": 14420,
    "preview": "# nimgame2/types.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "nimgame2/typewriter.nim",
    "chars": 3066,
    "preview": "# nimgame2/typewriter.nim\n# Copyright (c) 2016-2018 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free o"
  },
  {
    "path": "nimgame2/utils.nim",
    "chars": 12536,
    "preview": "# nimgame2/utils.nim\n# Copyright (c) 2016-2020 Vladimir Arabadzhi (Vladar)\n#\n# Permission is hereby granted, free of cha"
  },
  {
    "path": "nimgame2.nim",
    "chars": 1246,
    "preview": "import\n    nimgame2/nimgame,\n    nimgame2/draw,\n    nimgame2/entity,\n    nimgame2/settings,\n    nimgame2/audio,\n    nimg"
  },
  {
    "path": "nimgame2.nimble",
    "chars": 250,
    "preview": "# Package\n\nversion       = \"0.6.2\"\nauthor        = \"Vladar\"\ndescription   = \"A simple 2D game engine for Nim language.\"\n"
  }
]

// ... and 5 more files (download for full content)

About this extraction

This page contains the full source code of the Vladar4/nimgame2 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 195 files (2.8 MB), approximately 741.7k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!