;; Copyright (c) Camden Dixie O'Brien ;; SPDX-License-Identifier: AGPL-3.0-only (in-package :ham) (defclass simulation () ((state :initarg :start) (params :initarg :params) (width :initarg :width :initform 800) (height :initarg :height :initform 600) (running :initform nil) simulation-thread)) (defgeneric update (simulation dt)) (defgeneric render (simulation)) (defmethod initialize-instance :after ((sim simulation) &key) (start sim)) (defmethod run ((sim simulation)) (sdl2:make-this-thread-main (lambda () (with-slots (width height running) sim (with-graphics-context (ctx :width width :height height) (loop while running do (update sim (/ 1.0 60.0)) ; assume 60 Hz (let ((frame (render sim))) (display-frame ctx frame)))))))) (defmethod start ((sim simulation)) (with-slots (running simulation-thread) sim (setf running t) (setf simulation-thread (sb-thread:make-thread (lambda () (run sim)) :name "ham-simulation-thread")))) (defmethod stop ((sim simulation)) (with-slots (running simulation-thread) sim (setf running nil) (sb-thread:join-thread simulation-thread))) (defmacro define-simulation (name &key lagrangian coords render start params) `(progn (defclass ,name (simulation) () (:default-initargs :start ',start :params ',params)) (defmethod update ((sim ,name) dt) (with-slots (state params) sim (setf state ,(let ((eqns (hamilton-eqns lagrangian coords))) (update-body eqns coords params))))) (defmethod render ((sim ,name)) (with-slots (state) sim (let ,(mapcar (lambda (q) `(,q (getf state ',q))) coords) ,render)))))