All Projects → resttime → cl-liballegro

resttime / cl-liballegro

Licence: other
Common Lisp bindings and interface to the Allegro 5 game programming library

Programming Languages

common lisp
692 projects

Projects that are alternatives of or similar to cl-liballegro

Xamarin-iOS
PSPDFKit for iOS wrapper for the Xamarin platform.
Stars: ✭ 14 (-68.18%)
Mutual labels:  bindings
CloudBuildManifest
CloudBuildManifest is library to get build information for Unity Cloud Build.
Stars: ✭ 18 (-59.09%)
Mutual labels:  game-dev
interop
Python/C/Go/Rust/Haskell interop examples
Stars: ✭ 24 (-45.45%)
Mutual labels:  bindings
paka.cmark
Lightweight CFFI-based Python bindings to cmark library (CommonMark implementation in C).
Stars: ✭ 23 (-47.73%)
Mutual labels:  cffi
scala-native-bindgen
Scala Native Binding Generator
Stars: ✭ 29 (-34.09%)
Mutual labels:  bindings
OpenGL.NET
This repository contains low-level bindings for OpenGL and OpenGLES used in Evergine.
Stars: ✭ 29 (-34.09%)
Mutual labels:  bindings
mltools
MLDB Unity Editor Bindings
Stars: ✭ 22 (-50%)
Mutual labels:  bindings
harmony-ecs
A small archetypal ECS focused on compatibility and performance
Stars: ✭ 33 (-25%)
Mutual labels:  game-dev
webgl-raub
WebGL bindings to desktop OpenGL
Stars: ✭ 66 (+50%)
Mutual labels:  bindings
mmo-arch
Base Architecture for creating scalable games using microservices through Angular, Phaser, NestJS, NATS, and MySQL
Stars: ✭ 25 (-43.18%)
Mutual labels:  game-dev
bindingsrx
A 2 way binding system for unity using unirx
Stars: ✭ 109 (+147.73%)
Mutual labels:  bindings
nuklear4j
Java binding for nuklear
Stars: ✭ 61 (+38.64%)
Mutual labels:  bindings
sn-bindgen
Scala 3 native binding generator + libclang facade
Stars: ✭ 29 (-34.09%)
Mutual labels:  bindings
go-wlroots
Go binding for wlroots
Stars: ✭ 92 (+109.09%)
Mutual labels:  bindings
vsphere-automation-sdk-.net
[DEPRECATED] Please see README. C# samples, language bindings, and API reference documentation for vSphere, VMC, and NSX-T using the VMware REST API
Stars: ✭ 67 (+52.27%)
Mutual labels:  bindings
fltk-rs
Rust bindings for the FLTK GUI library.
Stars: ✭ 929 (+2011.36%)
Mutual labels:  bindings
x264-rs
x264 bindings
Stars: ✭ 32 (-27.27%)
Mutual labels:  bindings
05 TestingGrounds
A Hunger-Games inspired FPS with large outdoor terrains. Advanced AI, basic networking, pickups, skeletal meshes, checkpoints and more. (ref: TG_URC) http://gdev.tv/urcgithub
Stars: ✭ 121 (+175%)
Mutual labels:  game-dev
ripeatlas
Go bindings for RIPE Atlas API
Stars: ✭ 12 (-72.73%)
Mutual labels:  bindings
simdjson-rust
Rust bindings for the simdjson project.
Stars: ✭ 59 (+34.09%)
Mutual labels:  bindings

cl-liballegro

http://liballeg.org/images/logo.png

Interface and complete bindings to the Allegro 5 game programming library.

Check out how the source code is organized and compare it to the API reference.

Requires

libffi

Quickstart

  1. al_* becomes al:*
  2. Constants and types are shortened too, check the source code if you need help finding them
  3. (al:rest secs) is (al:rest-time secs) because of symbol clash with #'cl:rest
  4. To access slots from a C struct, you can use CFFI:MEM-REF generate a plist
    (defcstruct display-mode
      (width :int)
      (height :int)
      (format :int)
      (refresh-rate :int))
    
    (with-foreign-object (test '(:struct display-mode))
      (let ((plist (mem-ref test '(:struct display-mode))))
        (print plist)
        (print (getf plist 'width))))
        
  5. I’ve got a neat OPTIONAL lispy interface which provides an entire fixed timestep game loop
  6. Everything else is pretty much 1-to-1
  7. If you’re getting crashes on Mac OS X, put all your code into callback and pass it to al:run-main
  8. Examples exist if you get lost

Projects

Various projects I’ve found using cl-liballegro. Feel free to add items onto the list!

GUI / UI

Games

Engine

General

https://user-images.githubusercontent.com/2598904/96662425-f3c4cf00-1313-11eb-9e59-807e27697c20.png

The most basic usage is 1-to-1 just uses the bindings “as is” such as in this example.

Names have been changed to use a more lispy convention in which _ is converted to -. In most cases function names match like al_flip_display(display); becomes (al:flip-display display)

However types, constants, and structures have been shortened for user convenience. There’s no exact rules for it, but usually any prefix with ALLEGRO_* or al_* is truncated because Common Lisp has multiple namespaces to handle naming clashes. For the rare edge cases, check the source code.

Another change is that certain constants have been changed to Common Lisp keywords. Keyboard functions in C use an enum values corresponding to the key but cl-liballegro uses keywords instead. An example is ALLEGRO_KEY_K becoming :K. CFFI takes care of translating the value to the keyword and vice-versa. Using keywords over constants tends to be convenient in practice.

CFFI

Occasionally dropping down to a level lower using CFFI is necessary. One of these situations is passing a non-opaque data structure by reference.

Consider this block of C:

{
  ALLEGRO_EVENT event;
  bool running = true;
  while (running) process_event(&event);
}

In Common Lisp we will use CFFI to allocate the structure for the corresponding Allegro 5 functions. Remember to free up the memory afterwards!

(defparameter *running-p* t)
(let ((event (cffi:foreign-alloc '(:union al:event)))
  (loop while *running-p* do (process-event event))
  (cffi:foreign-free event))

Orphaned Windows / Cleaning up Windows

At times when something goes wrong the debugger pops up and a new window is created without the previous one being destroyed. This is due to how Common Lisp debugger restarts execution. One of the ways to handle this is wrapping things in an UNWIND-PROTECT or using the condition handlers in Common Lisp. Errors should be handled in such a way that restarts do not re-execute certain s-exps to create a new display. Errors can also be handled by cleaning up resources.

Optional Lisp Interface

An optional lisp interface is included with cl-liballegro which provides a full game loop with a fixed timestep and Entity Component System (ECS) implemented on the CLOS. Note that it is provided as is and not optimized. If performance is a concern, it is recommended to implement your own game loop while avoiding multiple dispatch and I will look forward to seeing your AAA game in the future.

  1. Define system which holds state
    ;; Creates a 800x600 resizable OpenGL display titled "Simple"
    ;; Fixed timestep loop runs logic at 1 FPS
    ;; The remaining time is spent on render
    ;;
    ;; The PREVIOUS-KEY slot is user-defined state for this example
    (defclass window (al:system)
      ((previous-key :initform "Nothing" :accessor previous-key))
      (:default-initargs
       :title "Simple"
       :width 800 :height 600
       :logic-fps 1
       :display-flags '(:windowed :opengl :resizable)
       :display-options '((:sample-buffers 1 :suggest)
                          (:samples 4 :suggest))))
        
  2. Implement Method for Logic
    (defmethod al:update ((sys window))
      (print 'one-logic-frame))
        
  3. Implement Method for Render
    (defmethod al:render ((sys window))
      (al:clear-to-color (al:map-rgb 20 150 100))
      (al:flip-display))
        
  4. Implement Methods(s) for Handler
    ;; The lisp interface uses this handler in the background of the logic
    (defmethod al:key-down-handler ((sys window))
      (let ((keyboard (cffi:mem-ref (al:event sys) '(:struct al:keyboard-event))))
        (print (getf keyboard 'al::keycode))
        (setf (previous-key sys) (getf keyboard 'al::keycode))))
        
  5. Run system
    (al:run-system (make-instance 'window)))
        

Mac OS X - Main UI Thread

Running on Mac OS X tends to behave oddly with threads because it requires GUI related code to run in the main thread (affects programs outside of Common Lisp too). The Allegro 5 library has a solution with al_run_main. Define a callback with defcallback and pass it to AL:RUN-MAIN.

;; First define a callback
(cffi:defcallback my-main :void ()
  ;; Code goes in here
  (function-with-gui-code))

;; Second execute by passing the callback to AL:RUN-MAIN
(al:run-main 0 (cffi:null-pointer) (cffi:callback my-main))

Ignoring Floating Point Calculation Errors / Traps

Common Lisp implementations tend to throw floating point calculation errors such as FLOATING-POINT-OVERFLOW and FLOATING-POINT-INVALID-OPERATION by default (called traps) to be explicitly handled rather than ignored. There are situations where this is valid behaviour but sometimes such errors get thrown despite valid code being called through the foreign function interface (FFI).

In this case it should be safe to ignore using implementation specific routines or the float-features portability library:

;; SBCL
;; Sets traps globally
(sb-int:set-floating-point-modes :traps (:invalid :inexact :overflow))

;; SBCL
;; Code wrapped in the macro ignores floating point errors in the list
(sb-int:with-float-traps-masked (:invalid :inexact :overflow)
  (function-with-floating-point-errors))

;; float-features (portability library)
;; Code wrapped in the macro ignores floating point errors in the list
(float-features:with-float-traps-masked (:divide-by-zero
                                         :invalid
                                         :inexact
                                         :overflow
                                         :underflow)
  (function-with-floating-point-errors))

Windows - Library Paths

There are path problems in Windows because the Allegro 5 library files which contain all the functions the CFFI calls upon do not have a default location unlike Unix environments. When the library is loaded under Windows, CFFI will look for the library files in the current folder of the FILE.LISP that evaluates (ql:quickload "cl-liballegro"). This means a copy of the library files must be in the directory of FILE.LISP, not in the cl-liballegro directory unless the FILE.LISP is in there. SLIME however, likes to change the default search folder to the one Emacs is in when it starts.

With SBCL

;; Open command prompt in the folder that contains both the DLL and game.lisp
> sbcl
> (load "game.lisp") ; File contains (ql:quickload "cl-liballegro")

With Emacs + SLIME

game.lisp contains (ql:quickload :cl-liballegro)

;; Looks for the DLL at /path/to/Desktop/allegro.dll
C-x C-f /path/to/Desktop/file9.lisp
M-x slime
C-x C-f /path/to/Desktop/game/game.lisp
C-c C-l
;; Looks for the DLL at /path/to/Desktop/game/allegro.dll
C-x C-f /path/to/Desktop/file9.lisp
C-x C-f /path/to/Desktop/game/game.lisp
M-x slime
C-c C-l
;; Looks for the DLL at /whatever/default/emacs/directory/allegro.dll
M-x slime
C-x C-f /path/to/Desktop/game/game.lisp
C-c C-l

Contributing / Developing / Hacking

cl-liballegro is organized according to the Allegro 5 Documentation with functions, types, and constants separated.

CFFI is used and its manual recommended to understand more advanced uses though not required for most cases.

Naming conventions has a preference for truncating ALLEGRO or al for user convenience since Common Lisp has multiple namespaces for resolving symbol names. For the rare edge cases, check the types and constants

Usage of keywords over enums preferred for user convenience.

Project Structure

Checklist

CHANGELOG

FYI these bindings are so stable it can make the repo look dead

Support / Help / Bug Reports

License

Project under zlib license

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].