jak-project/goal_src/jak3/lib/project-lib.gp
Hat Kid 62ef9fe49d
[wip] build actor tool (#3266)
This does a couple of things:

- The `custom_levels` folder was renamed to `custom_assets` and contains
`levels`, `models` and `texture_replacements` folders for Jak 1, 2 and 3
in order to keep everything regarding custom stuff in one place.
- With this, texture replacements now use separate folders for all games
- A build actor tool was added that generates art groups for custom
actors
- Custom levels can now specify what custom models from the `models`
folder they want to import, this will add them to the level's FR3.
- A `test-zone-obs.gc` file was added, containing a `test-actor` process
that uses a custom model as an example.

The build actor tool is still very WIP, the joints and the default
animation are hardcoded, but it allows for importing any GLB file as a
merc model.
2024-05-18 18:18:25 +02:00

254 lines
9.1 KiB
Scheme

;;-*-Lisp-*-
;; TODO extract most of this into a common lib that isn't so game dependent
;;;;;;;;;;;;;;;;;;;;;;;
;; Build system macros
;;;;;;;;;;;;;;;;;;;;;;;
(defun gc-file->o-file (filename)
"Get the name of the object file for the given GOAL (*.gc) source file."
(string-append "$OUT/obj/" (stem filename) ".o")
)
(defmacro goal-src (src-file &rest deps)
"Add a GOAL source file with the given dependencies"
`(let ((output-file ,(gc-file->o-file src-file)))
(set! *all-gc* (cons output-file *all-gc*))
(defstep :in ,(string-append "goal_src/jak3/" src-file)
;; use goal compiler
:tool 'goalc
;; will output the obj file
:out (list output-file)
;; dependencies are the obj files
:dep '(,@(apply gc-file->o-file deps))
)
)
)
(defun make-src-sequence-elt (current previous prefix)
"Helper for goal-src-sequence"
`(let ((output-file ,(gc-file->o-file current)))
(set! *all-gc* (cons output-file *all-gc*))
(defstep :in ,(string-append "goal_src/jak3/" prefix current)
:tool 'goalc
:out (list output-file)
:dep '(,(gc-file->o-file previous))
)
)
)
(defun make-src-sequence-elt-jak1 (current previous prefix)
"Helper for goal-src-sequence"
`(let ((output-file ,(gc-file->o-file current)))
(set! *all-gc* (cons output-file *all-gc*))
(defstep :in ,(string-append "goal_src/jak1/" prefix current)
:tool 'goalc
:out (list output-file)
:dep '(,(gc-file->o-file previous))
)
)
)
;; TODO - deps should probably just treated as a proper list to refactor duplication
(defmacro goal-src-sequence (prefix &key (deps '()) &rest sequence)
"Add a sequence of GOAL files (each depending on the previous) in the given directory,
with all depending on the given deps."
(let* ((first-thing `(goal-src ,(string-append prefix (first sequence)) ,@deps))
(result (cons first-thing '()))
(iter result))
(let ((prev (first sequence))
(in-iter (rest sequence)))
(while (not (null? in-iter))
;; (fmt #t "{} dep on {}\n" (first in-iter) prev)
(let* ((cur-src-file (first in-iter))
;; grotesque temp hack
(next (if (or (eq? "pc/pckernel-h.gc" cur-src-file)
(eq? "pc/pckernel-common.gc" cur-src-file)
(eq? "pc/debug/pc-debug-common.gc" cur-src-file))
(make-src-sequence-elt-jak1 cur-src-file prev prefix)
(make-src-sequence-elt cur-src-file prev prefix))))
(set-cdr! iter (cons next '()))
(set! iter (cdr iter))
)
(set! prev (car in-iter))
(set! in-iter (cdr in-iter))
)
)
`(begin ,@result)
)
)
(defun cgo (output-name desc-file-name)
"Add a CGO with the given output name (in $OUT/iso) and input name (in goal_src/jak3/dgos)"
(let ((out-name (string-append "$OUT/iso/" output-name)))
(defstep :in (string-append "goal_src/jak3/dgos/" desc-file-name)
:tool 'dgo
:out `(,out-name)
)
(set! *all-cgos* (cons out-name *all-cgos*))
)
)
(defun tpage-name (id)
"Get the name of the tpage obj file with the given id"
(fmt #f "tpage-{}.go" id)
)
(defmacro copy-texture (tpage-id)
"Copy a texture from the game, using the given tpage ID"
(let* ((path (string-append "$DECOMP/raw_obj/" (tpage-name tpage-id))))
`(defstep :in ,path
:tool 'copy
:out '(,(string-append "$OUT/obj/" (tpage-name tpage-id))))))
(defmacro copy-textures (&rest ids)
`(begin
,@(apply (lambda (x) `(copy-texture ,x)) ids)
)
)
(defmacro copy-obj (name)
(let* ((path (string-append "$DECOMP/raw_obj/" name)))
`(defstep :in ,path
:tool 'copy
:out '(,(string-append "$OUT/obj/" name)))))
(defmacro copy-objs (&rest gos)
`(begin
,@(apply (lambda (x) `(copy-obj ,x)) gos)
)
)
(defmacro group (name &rest stuff)
`(defstep :in ""
:tool 'group
:out '(,(string-append "GROUP:" name))
:dep '(,@stuff))
)
(defun group-list (name stuff)
(defstep :in ""
:tool 'group
:out `(,(string-append "GROUP:" name))
:dep stuff)
)
(defun copy-iso-file (name subdir ext)
(let* ((path (string-append "$ISO/" subdir name ext))
(out-name (string-append "$OUT/iso/" name ext)))
(defstep :in path
:tool 'copy
:out `(,out-name))
out-name))
(defmacro copy-strs (&rest strs)
`(begin ,@(apply (lambda (x) `(set! *all-str* (cons (copy-iso-file ,x "STR/" ".STR") *all-str*))) strs)))
(defmacro copy-sbk-files (&rest files)
`(begin ,@(apply (lambda (x) `(set! *all-sbk* (cons (copy-iso-file ,x "SBK/" ".SBK") *all-sbk*))) files)))
(defmacro copy-mus-files (&rest files)
`(begin ,@(apply (lambda (x) `(set! *all-mus* (cons (copy-iso-file ,x "MUS/" ".MUS") *all-mus*))) files)))
(defmacro copy-vag-files (&rest files)
`(begin ,@(apply (lambda (x) `(set! *all-vag* (cons (copy-iso-file "VAGWAD" "VAG/" (string-append "." ,x)) *all-vag*))) files)))
(defun reverse-list (list)
(let ((new-list '())
(curr-elt list))
(while (not (null? curr-elt))
(set! new-list (cons (car curr-elt) new-list))
(set! curr-elt (cdr curr-elt)))
new-list))
(defmacro cgo-file (dgo-file-name deps &key (bsp-file-name #f))
;; First read in the DGO file, it has pretty much everything we need
(let ((dgo-data (car (read-data-file (string-append "goal_src/jak3/dgos/" dgo-file-name)))))
;; Get the name of the DGO
(let ((dgo-name (car dgo-data))
(files (cadr dgo-data))
(gsrc-seq-args '())
(textures '())
(objs '()))
;; create the dgo step
(cgo dgo-name dgo-file-name)
;; Now we iterate through the list of files, skipping ones we've already processed
;; and creating steps for the ones that are new!
(while (not (null? files))
(let ((file-name (car files)))
;; Check to see if we've already handled this file
(when (not (car (hash-table-try-ref *file-entry-map* file-name)))
;; Depending on the type of file, generate the appropriate steps
(cond
((and (string-ends-with? file-name ".o")
(neq? file-name bsp-file-name)
)
;; build up a list of all gsrc files needing to be compiled
(let ((base-name (symbol->string (first (string-split file-name ".")))))
(cond
;; hardcoded cases to grab from jak1... really dont want to copy-paste these all the time!
((or (eq? base-name "pckernel-h")
(eq? base-name "pckernel-common")
(eq? base-name "pc-debug-common"))
(let ((old-path (get-gsrc-folder))
(gsrc-path (begin (set-gsrc-folder! "goal_src/jak1")
(get-gsrc-path base-name))))
(set! gsrc-seq-args (cons gsrc-path gsrc-seq-args))
(set-gsrc-folder! old-path)
)
)
(#t
(let ((gsrc-path (get-gsrc-path base-name)))
(set! gsrc-seq-args (cons gsrc-path gsrc-seq-args)))
)
))
)
((string-starts-with? file-name "tpage-")
;; copy textures
(let ((tpage-id (second (string-split (symbol->string (first (string-split file-name "."))) "-"))))
(set! textures (cons tpage-id textures))))
((or (string-ends-with? file-name ".go")
(eq? file-name bsp-file-name)
)
;; copy art files
(set! objs (cons file-name objs))))
;; Update the map so this file isn't processed again
(hash-table-set! *file-entry-map* file-name #f)))
(set! files (cdr files)))
;; TODO - need an `append`!, reverse lists by re-cons'ing them for now
(set! gsrc-seq-args (reverse-list gsrc-seq-args))
(set! textures (reverse-list textures))
(set! objs (reverse-list objs))
`(begin
;; macros can't return nothing, so these macros assume they will be given a non-empty list
(when (not (null? '(,@gsrc-seq-args)))
(goal-src-sequence "" :deps ,(eval deps) ,@gsrc-seq-args))
(when (not (null? '(,@textures)))
(copy-textures ,@textures))
(when (not (null? '(,@objs)))
(copy-objs ,@objs)))
)
))
(defun custom-level-cgo (output-name desc-file-name)
"Add a CGO with the given output name (in $OUT/iso) and input name (in custom_assets/jak3/levels/)"
(let ((out-name (string-append "$OUT/iso/" output-name)))
(defstep :in (string-append "custom_assets/jak3/levels/" desc-file-name)
:tool 'dgo
:out `(,out-name)
)
(set! *all-cgos* (cons out-name *all-cgos*))
)
)
(defmacro build-custom-level (name)
(let* ((path (string-append "custom_assets/jak3/levels/" name "/" name ".jsonc")))
`(defstep :in ,path
:tool 'build-level3
:out '(,(string-append "$OUT/obj/" name ".go")))))