Table of Contents
Resources
The system pyssel/resource holds resources: data kept in files of their
own or inside the files that use them, loaded once and shared, as Godot's
resources are. define-resource defines a resource class, whose
properties work as nodes' do, and save-resource and load-resource save
and load one, here the arena's stats of Saving Scenes:
(res:save-resource (make-instance 'stats :health 6) "brute.resource")
(stats-health (res:load-resource "brute.resource")) ; => 6
A resource that has a file of its own, its resource-path, is saved as a
reference to that file, relative to the file that refers to it; one that
has none is kept inside, once however many properties hold it, as stats
is in the arena.scene of Saving Scenes. load-resource gives the same object for the
same file while anything holds it, unless something else wrote the file
since. Each session has its own cache, so a game played in
the editor's image loads copies of its own, and what it changes in them
stays its own. A packed scene is a resource too, so a scene that many
levels hold is loaded once.
A value class, which define-value-class defines, makes objects with
properties that are kept inside the files of whatever holds them, by
value, as a menu's items are: each is saved as (:object (class initarg value...)), with the properties that differ from a new one's, and has no
file of its own, so loading makes every holder an object of its own.
resource-changed-p tells whether a resource holds what its file does,
comparing what saving would write with the file's form, so how the file
is laid out does not count; resource-file-changed-p whether something
else wrote the file since the resource was loaded or saved, which saving
would overwrite; and revert-resource reads the file into the same
object again, so whatever holds it sees the file's values. The editor
saves and throws away changes to resources so:
(let ((brute (res:load-resource "brute.resource")))
(setf (stats-health brute) 99)
(list (res:resource-changed-p brute) ; => T
(stats-health (res:revert-resource brute)) ; => 6
(res:resource-changed-p brute))) ; => NIL
Files can move under a running editor, and it keeps them referring to
each other, as the File System dock does:
file-references lists the files a file of Pyssel's format refers to,
absolute, reading its form without loading it; retarget-file-references
rewrites the paths a file refers to others by, given a function that
returns where each file is now, and, with :from, where the file itself
was before it moved, each path written relative to the file as saving
writes it; resource-file-moved has the resources loaded from a file, or
from the files under a folder, follow them to where they are, the same
objects, which loading their new paths gives; and resource-file-deleted
lets them go of their files, so whatever holds them keeps them inside
its own file when it is saved.
property-value reads a property of a node or a resource by its name, as
class-properties gives it, and setf of it sets one as code would,
through the class's own setter, which checks the value and acts on it, as
a node draws itself again: the inspector and the editor's histories work
so. It takes any real for a float property, as make-instance and
loading a file do. A class whose property holds an object it changes in
place, as a 2D node's position vector, gives a copy, so a value read stays
as it was; one whose property is made when asked for, as a text edit's
text from its lines, makes it. Saving and reverting read properties
through property-value too. property-type gives a property's type as
its class declared it, and property-hint its hint.
A resource class checks what make-instance's initargs give its
properties against their types, as a node class does (see
Scene Tree), in words read from the types, and its slots
take :copy too, to keep a copy of what an initarg gives them.
A slot of a float type takes :cell t, to keep its value in a
res:cell, an array of one float, changed in place, so that a
double-float that changes each frame changes without allocating: Lisp
keeps a double-float in a slot as an object of its own, made anew each
time the slot is set. The slot's readers return the cell, and
property-value reads and sets the float in it; the class reads and sets
it with inline functions of its own, as a 2D node's node-rotation does:
(res:define-object spinner ()
((angle :initarg :angle :initform 0d0 :type double-float :cell t
:reader angle-cell :property t)))
(declaim (inline spinner-angle (setf spinner-angle)))
(defun spinner-angle (spinner)
(aref (the (res:cell double-float) (angle-cell spinner)) 0))
(defun (setf spinner-angle) (angle spinner)
(setf (aref (the (res:cell double-float) (angle-cell spinner)) 0)
(float angle 1d0)))
A subclass that gives such a slot a type or an initform says :cell t
too. A tween of the property allocates nothing when the class
gives it the cell with property-place.
A
resource has signals, which its class names with (:signals ...), as Godot's ButtonGroup has pressed.
duplicate-resource copies a resource, as Godot's duplicate and
duplicate_deep do: a new resource of its class, with no file, made from
its properties. A shallow copy, the default, holds the same lists,
vectors, value objects and resources; :deep t copies them and what they
hold, the resources among them as :subresources says: :internal, the
default, those with no file of their own, :all every one, :none none.
Each is copied once, so two properties that held one hold one copy:
(let* ((brute (res:load-resource "brute.resource"))
(stronger (res:duplicate-resource brute)))
(setf (stats-health stronger) 12)
(list (stats-health brute) (res:resource-path stronger))) ; => (6 NIL)
Files of other formats are resources too, read by the methods of
read-resource-file for their type, cached the same way, and only loaded:
a resource that holds one refers to its file. The system pyssel/font
loads font files, .ttf, .otf and .ttc, as font-file resources, and
font-at gives one at a size for drawing text, as Godot's FontFile does.
A font-variation draws a variable font with values of its axes, such as
a weight, and is saved as resources are:
(asdf:load-system :pyssel/font)
;; In a package with (#:pf #:pyssel/font) among its local nicknames:
(res:save-resource (make-instance 'pf:font-variation :base (res:load-resource "fonts/Inter.ttf")
:variations '(("wght" . 700)))
"fonts/inter-bold.resource")
(defun title (canvas) ; a canvas's draw function
(p2d:draw-text canvas "Title" 10 10
(pf:font-at (res:load-resource "fonts/inter-bold.resource") 20) '(1 1 1)))
The variation is a resource of its own, so the canvas asks for it by its file, and loading it again gives the same object while anything holds it. A font file is read into memory once. Its foreign objects and what the renderers made from its glyphs are freed once nothing holds the font, its sizes, or a canvas that draws it.
Getting started
The core
Drawing
Scenes
User interface
Games and the editor
- Playing a Game
- Projects
- The Editor
- The File System Dock
- The Script Screen
- The REPL
- The Debugger
- Lisp Text
- Code Services
- Project Manager
- Undo and Redo
- Exporting
The project