diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..5aaf59e --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,22 @@ +FROM debian:trixie +RUN apt update +RUN apt upgrade + +ENV DISPLAY=:0 + +# Install chicken +RUN apt install -y build-essential git +RUN apt install -y chicken-bin + +# Install chicken tools +RUN chicken-install beaker csm + +# Install raylib +RUN apt install -y libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev libwayland-dev libxkbcommon-dev +RUN git clone --depth 1 https://github.com/raysan5/raylib.git raylib && \ +cd raylib/src/ && \ +make PLATFORM=PLATFORM_DESKTOP && \ +make install + +# Install egg dependencies +RUN chicken-install -from-list deps.lock \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..3cd4515 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,12 @@ +{ + "name": "Imugi Dev Container", + "build": { + "dockerfile": "Dockerfile" + }, + "runArgs": [ + "--net", "host", + "-e", "DISPLAY=:0", + "-e", "XAUTHORITY=/tmp/.Xauthority", + "-v", "${localEnv:HOME}/.Xauthority:/tmp/.Xauthority" + ] +} diff --git a/COLLABORATION.org b/COLLABORATION.org new file mode 100644 index 0000000..36a7956 --- /dev/null +++ b/COLLABORATION.org @@ -0,0 +1,26 @@ +#+title: Collaboration + +Imugi can be easily built without any local chicken scheme installation by using the devcontainer spec included in this repository. + +* Using the Devcontainers CLI +First, run ~npm install -g @devcontainers/cli~ to install the devcontainers CLI tool. + +This requires a working Docker installation, the steps to which can be found [[https://docs.docker.com/engine/install/][here]]. Also assign your user to the ~docker~ group to avoid having to use ~sudo~ with docker and devcontainer commands. + +Once both of the above are installed, the devcontainer can be started with ~devcontainer up --workspace-folder .~ in the repository root. This will build a Debian Trixie container including all Chicken dependencies, and also build Raylib as a static library. We prefer to build with static linking in order to make distribution less annoying. + +Once the devcontainer is running, enter it with ~devcontainer exec --workspace-folder . bash~. This will put you at the repository root. + +* Dependencies +The ~deps.lock~ file contains the versions of eggs used in this repository. They can be installed with ~chicken-install -from-list deps.lock~. + +* Collaborating with Emacs +The ~.dir-locals.el~ file automatically sets the Geiser Scheme implementation to Chicken, for any Scheme source file in this directory. + +* Running Tests & Samples +From the ~build~ directory, run ~csm -program ..~ to build a particular module, the ~./~ to run it. + +Any module defined in the ~samples~ or ~test~ directory can be run like this, either to show an example game or to run tests for a particular engine module. + + If you are running the devcontainer on an X11 Linux host, running the compiled module should forward the window to your hosts X11 display. YMMV for Wayland and non-Linux hosts. + diff --git a/README.org b/README.org index b81e1ec..b042912 100644 --- a/README.org +++ b/README.org @@ -2,6 +2,30 @@ Imugi is a framework for building games (primarily tactics games) with Chicken Scheme and raylib. The end goal of this framework is to create a game, also called Imugi, and release to show the capability here. +* Installation & Usage +Raylib must first be installed before you can get started with Imugi. + +Note: this guide assumes static linking for the Raylib library. + +Install raylib statically using the following commands: +#+begin_src shell + git clone --depth 1 https://github.com/raysan5/raylib.git raylib + cd raylib/src/ + make PLATFORM=PLATFORM_DESKTOP + make install +#+end_src + +The following dependencies are required on Debian: +#+begin_src shell + apt install -y libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev libwayland-dev libxkbcommon-dev +#+end_src + +Once raylib is installed, run ~chicken-install -s~ in this directory to install all dependencies and the Imugi egg itself. + +You can then import the Imugi modules required in your project. + +When building your project, use the flags specified in ~all.options~ in this repository, which includes are the dependency links necessary. + * Architecture Imugi is an ECS engine. @@ -184,16 +208,3 @@ Functions for evaluating the render queues. ~evaluate-render-queue~ evaluates a (create-window process: (next-frame) close-predicate: (window-should-close?)) #+end_src ~create-window~ creates a window using the window parameters described above, sets the target frames per second, then enters a loop which runs the ~process:~ function (~next-frame~ by default) on each frame, unless ~close-predicate:~ (Raylib's ~window-should-close~ function by default) returns true, in which case the window is closed. - -* Dependencies -The following Chicken dependencies are required: -- raylib -- SRFI-99 -- SRFI-113 -- SRFI-69 -- csm -- SRFI-78 - -* Running -From the ~build~ directory, run ~csm -program test.engine .. && ./test.engine~ to run engine tests. - diff --git a/all.options b/all.options index 4efc2d9..a6db636 100644 --- a/all.options +++ b/all.options @@ -1 +1 @@ --static -L /usr/local/lib64/libraylib.a \ No newline at end of file +-static -L /usr/local/lib/libraylib.a -L -lX11 -L -lXrandr -L -lXi -L -lXcursor -L -lXinerama -L -lXext -L -lGL -L -lm -L -lpthread -L -ldl -L -lrt \ No newline at end of file diff --git a/deps.lock b/deps.lock new file mode 100644 index 0000000..5740b68 --- /dev/null +++ b/deps.lock @@ -0,0 +1,14 @@ +("raylib" "1.2.0") +("srfi-1" "0.5.1") +("r7rs" "1.0.12") +("srfi-69" "0.4.3") +("matchable" "1.2") +("srfi-113" "2.0.0") +("foreigners" "1.5") +("srfi-99" "1.4.5") +("srfi-14" "0.2.1") +("miscmacros" "1.0") +("srfi-78" "0.5") +("srfi-42" "1.76") +("srfi-128" "0.11") +("srfi-13" "0.3.4") diff --git a/engine/components.scm b/engine/components.scm index 87b12c8..ba3b3df 100644 --- a/engine/components.scm +++ b/engine/components.scm @@ -1,10 +1,10 @@ -(module (engine components core) () +(module (imugi components core) () (import scheme (chicken base) (chicken module) - (engine core) - (engine guards) - (engine math) + (imugi core) + (imugi guards) + (imugi math) (srfi 1) (srfi 99)) diff --git a/engine/core.scm b/engine/core.scm index 613aa9d..e5e3a45 100644 --- a/engine/core.scm +++ b/engine/core.scm @@ -1,9 +1,9 @@ -(module (engine core) () +(module (imugi core) () (import scheme (chicken base) (chicken module) (chicken sort) - (engine guards) + (imugi guards) raylib (srfi 1) (srfi 4) @@ -429,11 +429,55 @@ (end-mode-3d))) (hash-table-set! render-queues queue-name '()))) +;; Resource queue +(export resource-load-queue resource-unload-queue) +(define resource-load-queue '()) +(define resource-unload-queue '()) + +(export make-resource resource? resource-type resource-contents resource-initialized? resource-initializer resource-finalizer set-resource-contents! set-resource-initialized!) +(define-record-type + (int:make-resource type struct initialized? initializer finalizer) + resource? + (type resource-type) + (struct resource-contents set-resource-contents!) + (initialized? resource-initialized? set-resource-initialized!) + (initializer resource-initializer) + (finalizer resource-finalizer)) + +(define (add-resource res) + (assert (resource? res)) + (set! resource-load-queue (cons res resource-load-queue))) + +(define (make-resource type struct initialized? initializer finalizer) + (assert (member type '(font texture))) + (assert (boolean? initialized?)) + (assert (procedure? initializer)) + (assert (procedure? finalizer)) + (let ((r (int:make-resource type struct initialized? initializer finalizer))) + (add-resource r) + r)) + +(define (load-queued-resources) + (for-each + (lambda (res) + ((resource-initializer res) res) + (set! resource-unload-queue (cons res resource-unload-queue))) + resource-load-queue) + (set! resource-load-queue '())) + +(define (unload-queued-resources) + (for-each + (lambda (res) + ((resource-finalizer res) res)) + resource-unload-queue) + (set! resource-unload-queue '())) + ;; Frame generation and game loop (export resolve-queues next-frame *clear-color* perform-render) ;; Resolve the entity and system queues. This is exported which allows breaking iteration (define (resolve-queues) + (load-queued-resources) (resolve-entity-queue) (resolve-system-queue)) @@ -483,5 +527,6 @@ (process) (unless (close-predicate) (loop))) + (unload-queued-resources) (close-window)) ) diff --git a/engine/drawing.scm b/engine/drawing.scm index 1b23039..5a6342a 100644 --- a/engine/drawing.scm +++ b/engine/drawing.scm @@ -1,10 +1,11 @@ -(module (engine drawing) () +(module (imugi drawing) () (import scheme (chicken base) (chicken module) raylib - (engine guards) - (engine math) + (imugi core) + (imugi guards) + (imugi math) (srfi 4) (srfi 99)) @@ -24,10 +25,10 @@ ;; Get a raylib color vec from a color (define (use-color col) (assert (color? col)) - (u8vector (floor (* 255 (color-r col))) - (floor (* 255 (color-g col))) - (floor (* 255 (color-b col))) - (floor (* 255 (color-a col))))) + (u8vector (number->integer (* 255 (color-r col))) + (number->integer (* 255 (color-g col))) + (number->integer (* 255 (color-b col))) + (number->integer (* 255 (color-a col))))) ;; Type safe color constructor (define (make-color r g b a) @@ -237,7 +238,7 @@ ;; Drawing functions ;; Helper wrappers for raylib functions -(export draw-circle-2d draw-rectangle-2d draw-text-2d) +(export draw-circle-2d draw-rectangle-2d draw-text-2d draw-texture-2d draw-font-text-2d) (define (draw-circle-2d pos-vec radius color filled) (assert (vec2? pos-vec)) (assert (number? radius)) @@ -282,4 +283,32 @@ (number->integer (v-y pos-vec)) size (use-color tint))) - ) + +(define (draw-font-text-2d pos-vec text size tint font) + (assert (vec2? pos-vec)) + (assert (string? text)) + (assert (resource? font)) + (assert (eqv? 'font (resource-type font))) + (assert ((conjoin integer? positive?) size)) + (assert (color? tint)) + (when (resource-initialized? font) + (draw-text-ex + (resource-contents font) + text + (make-vec2 (number->integer (v-x pos-vec)) + (number->integer (v-y pos-vec))) + size + 1 + (use-color tint)))) + +(define (draw-texture-2d pos-vec texture color) + (assert (vec2? pos-vec)) + (assert (resource? texture)) + (assert (eqv? 'texture (resource-type texture))) + (assert (color? color)) + (when (resource-initialized? texture) + (draw-texture (resource-contents texture) + (number->integer (v-x pos-vec)) + (number->integer (v-y pos-vec)) + (use-color color)))) +) diff --git a/engine/guards.scm b/engine/guards.scm index 844075b..c495e83 100644 --- a/engine/guards.scm +++ b/engine/guards.scm @@ -1,4 +1,4 @@ -(module (engine guards) () +(module (imugi guards) () (import scheme (chicken base) (chicken module) diff --git a/engine/input.scm b/engine/input.scm index 0cf6abe..9d63110 100644 --- a/engine/input.scm +++ b/engine/input.scm @@ -1,8 +1,8 @@ -(module (engine input) () +(module (imugi input) () (import scheme (chicken base) (chicken module) - (engine core) + (imugi core) raylib (srfi 99)) diff --git a/engine/math.scm b/engine/math.scm index ca82e91..5f1a186 100644 --- a/engine/math.scm +++ b/engine/math.scm @@ -1,4 +1,4 @@ -(module (engine math) () +(module (imugi math) () (import scheme (chicken base) (chicken module) diff --git a/engine/resource.scm b/engine/resource.scm new file mode 100644 index 0000000..ba11516 --- /dev/null +++ b/engine/resource.scm @@ -0,0 +1,48 @@ +(module (imugi resource) () +(import scheme + (chicken base) + (chicken module) + (chicken gc) + raylib + (srfi 69) + (imugi core)) + +(export font) +(define fonts (make-hash-table)) + +(define (font filename) + (assert (string? filename)) + (if (hash-table-exists? fonts filename) + (hash-table-ref fonts filename) + (let ((f (make-resource 'font '() + #f + (lambda (res) + (set-resource-contents! res (load-font filename)) + (set-resource-initialized! res #t)) + (lambda (res) + (hash-table-delete! fonts filename) + (unload-font (resource-contents res)) + (set-resource-initialized! res #f))))) + (hash-table-set! fonts filename f) + f))) + +(export texture) +(define textures (make-hash-table)) + +(define (texture filename) + (assert (string? filename)) + (if (hash-table-exists? textures filename) + (hash-table-ref textures filename) + (let ((t (make-resource 'texture '() + #f + (lambda (res) + (set-resource-contents! res (load-texture filename)) + (set-resource-initialized! res #t)) + (lambda (res) + (hash-table-delete! textures filename) + ;; TODO: uncomment this when possible + ;; (unload-texture (resource-contents res)) ; at time of writing, this is not yet in the raylib egg + (set-resource-initialized! res #f))))) + (hash-table-set! textures filename t) + t))) +) diff --git a/engine/scene.scm b/engine/scene.scm index f272e02..8326ec0 100644 --- a/engine/scene.scm +++ b/engine/scene.scm @@ -1,8 +1,8 @@ -(module (engine scene) () +(module (imugi scene) () (import scheme (chicken base) (chicken module) - (engine core) + (imugi core) (srfi 1) (srfi 99)) diff --git a/imugi.egg b/imugi.egg new file mode 100644 index 0000000..785b5b5 --- /dev/null +++ b/imugi.egg @@ -0,0 +1,23 @@ +((author "Jakub Nowak") + (synopsis "ECS system built on Raylib") + (version "0.1") + (license "AGPL") + (category graphics) + (dependencies raylib srfi-1 srfi-69 srfi-113 srfi-99) + (components + (extension imugi.guards + (source "engine/guards.scm")) + (extension imugi.core + (source "engine/core.scm")) + (extension imugi.math + (source "engine/math.scm")) + (extension imugi.components.core + (source "engine/components.scm")) + (extension imugi.drawing + (source "engine/drawing.scm")) + (extension imugi.resource + (source "engine/resource.scm")) + (extension imugi.input + (source "engine/input.scm")) + (extension imugi.scene + (source "engine/scene.scm")))) diff --git a/samples/bounce.scm b/samples/bounce.scm index 0d93c18..ad63ca1 100644 --- a/samples/bounce.scm +++ b/samples/bounce.scm @@ -2,12 +2,12 @@ (import scheme (chicken base) raylib - (engine core) - (engine components core) - (engine math) - (engine input) - (engine drawing) - (engine scene) + (imugi core) + (imugi components core) + (imugi math) + (imugi input) + (imugi drawing) + (imugi scene) (srfi 1) (srfi 99)) diff --git a/samples/resources/NothingYouCouldDo.ttf b/samples/resources/NothingYouCouldDo.ttf new file mode 100644 index 0000000..b086bce Binary files /dev/null and b/samples/resources/NothingYouCouldDo.ttf differ diff --git a/samples/resources/OFL.txt b/samples/resources/OFL.txt new file mode 100644 index 0000000..2d9ac5d --- /dev/null +++ b/samples/resources/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2010, Kimberly Geswein (kimberlygeswein.com) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/samples/resources/smiley.png b/samples/resources/smiley.png new file mode 100644 index 0000000..0e95d8b Binary files /dev/null and b/samples/resources/smiley.png differ diff --git a/samples/textures.scm b/samples/textures.scm new file mode 100644 index 0000000..06bcc5b --- /dev/null +++ b/samples/textures.scm @@ -0,0 +1,50 @@ +(module (textures) () +(import scheme + raylib + (chicken base) + (imugi core) + (imugi resource) + (imugi scene) + (imugi math) + (imugi drawing)) + +(define draw-smiley + (make-system + 'draw-smiley + 0 + 'global + '() + (lambda () + (push-render-object 'screen + 0 + (lambda () + (draw-texture-2d + (vec 0 0) + (texture "../samples/resources/smiley.png") + (make-color 1 1 1 1))))))) + +(define draw-smiley-text + (make-system + 'draw-text + 0 + 'global + '() + (lambda () + (push-render-object 'screen + 1 + (lambda () + (draw-font-text-2d + (vec 100 500) + "Hello there..." + 64 + (make-color 0 0 0 1) + (font "../samples/resources/NothingYouCouldDo.ttf"))))))) + +(define (demo) + (scene + draw-smiley + draw-smiley-text)) + +((demo)) +(create-window) +) diff --git a/samples/tic-tac-toe.scm b/samples/tic-tac-toe.scm index 65b3ed3..e132789 100644 --- a/samples/tic-tac-toe.scm +++ b/samples/tic-tac-toe.scm @@ -2,12 +2,12 @@ (import scheme (chicken base) (chicken random) - (engine core) - (engine math) - (engine components core) - (engine drawing) - (engine input) - (engine scene) + (imugi core) + (imugi math) + (imugi components core) + (imugi drawing) + (imugi input) + (imugi scene) raylib (srfi 1) (srfi 99))