;;-*-Lisp-*- (in-package goal) ;; name: collide-shape-h.gc ;; name in dgo: collide-shape-h ;; dgos: GAME, ENGINE ;; What is collide-shape? ;; A collide shape is a group of collision geometry. Typically, each actor will have a single collide shape. ;; Each collide shape may contain a number of collide-shape-prim's. ;; There are many subclasses of collide-shape-prim for different types of collision primitives. ;; Some subclasses can contain multiple collide-shape-prims. (declare-type touching-list structure) (declare-type collide-shape-prim basic) ;;;;;;;;;;;;;;;;;;; ;; Sticky Rider ;;;;;;;;;;;;;;;;;;; ;; Rider: thing which rides on a moving thing. For example, Jak is a rider of the platforms. ;; Sticky: when you hit the platform, your velocity immediately changes to match the thing. ;; like when Jak lands on a platform. (deftype collide-sticky-rider (structure) ((rider-handle handle :offset-assert 0) (sticky-prim collide-shape-prim :offset-assert 8) (prim-ry float :offset-assert 12) (rider-local-pos vector :inline :offset-assert 16) ) :method-count-assert 10 :size-assert #x20 :flag-assert #xa00000020 (:methods (set-rider! (_type_ handle) symbol 9) ) ) (defmethod set-rider! collide-sticky-rider ((obj collide-sticky-rider) (arg0 handle)) "Set the rider and clear the primitive." (set! (-> obj rider-handle) arg0) (set! (-> obj sticky-prim) #f) #f ) ;; A collection of collide-sticky-riders ;; dynamic type. There's one collide-sticky-rider per rider. (deftype collide-sticky-rider-group (basic) ((num-riders int32 :offset-assert 4) (allocated-riders int32 :offset-assert 8) (rider collide-sticky-rider 1 :inline :offset-assert 16) ) :method-count-assert 11 :size-assert #x30 :flag-assert #xb00000030 (:methods (new (symbol type int) _type_ 0) (add-rider! (_type_ process-drawable) collide-sticky-rider 9) (reset! (_type_) int 10) ) ) (defmethod reset! collide-sticky-rider-group ((obj collide-sticky-rider-group)) "Reset all active riders" (set! (-> obj num-riders) 0) 0 ) ;; The rider will be pulled along by the object. ;; This includes possibly rotating the rider (if the platform spins, it spins Jak too). (deftype pull-rider-info (structure) ((rider collide-sticky-rider :offset-assert 0) (rider-cshape collide-shape-prim :offset-assert 4) ;; maybe just collide-shape (rider-delta-ry float :offset-assert 8) (rider-dest vector :inline :offset-assert 16) ) :method-count-assert 9 :size-assert #x20 :flag-assert #x900000020 ) ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Collision Result ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Most general collision result from colliding two collide shapes ;; this computes a "move-vec" and "u". If you move along "move-vec" by "u", you will move out of collsion. ;; It also tells you which primitives are colliding. (deftype collide-shape-intersect (basic) ((move-vec vector :inline :offset-assert 16) (best-u float :offset-assert 32) (best-tri collide-tri-result :inline :offset-assert 48) (best-from-prim collide-shape-prim :offset-assert 132) (best-to-prim collide-shape-prim :offset-assert 136) ) :method-count-assert 10 :size-assert #x8c :flag-assert #xa0000008c (:methods (init! (_type_ vector) symbol 9) ) ) ;; Collision with just overlap distance, no vector. (deftype collide-overlap-result (structure) ((best-dist float :offset-assert 0) (best-from-prim collide-shape-prim :offset-assert 4) (best-to-prim collide-shape-prim :offset-assert 8) (best-from-tri collide-tri-result :inline :offset-assert 16) ) :method-count-assert 10 :size-assert #x64 :flag-assert #xa00000064 (:methods (reset! (_type_) none 9) ) ) (defmethod reset! collide-overlap-result ((obj collide-overlap-result)) "Reset the result." (set! (-> obj best-dist) 0.0) (set! (-> obj best-from-prim) #f) (set! (-> obj best-to-prim) #f) (none) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Touching System ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; I believe this overlaps-others-params is used to do checks like "is enemy in range of attack". ;; but this isn't well understood yet (deftype overlaps-others-params (structure) ((options uint32 :offset-assert 0) (tlist touching-list :offset-assert 4) ) :method-count-assert 9 :size-assert #x8 :flag-assert #x900000008 ) ;; The engine system is used to link collision checks with processes. ;; This allows you to have lists of processes where the process will remove itself when it dies. (define *collide-hit-by-player-list* (new 'global 'engine 'collide-hit-by-player-list 768)) (define *collide-usually-hit-by-player-list* (new 'global 'engine 'collide-usually-hit-by-player-list 256)) (define *collide-hit-by-others-list* (new 'global 'engine 'collide-hit-by-others-list 96)) (define *collide-player-list* (new 'global 'engine 'collide-player-list 32)) (defenum collide-list-enum (hit-by-player) (usually-hit-by-player) (hit-by-others) (player) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Collision Primitive Base ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; These are the settings that can be set per primtive. (defenum collide-kind :type uint64 :bitfield #t (background 0) (cak-1 1) ;; (cak-2 2) (cak-3 3) (target 4) ;; target (water 5) (powerup 6) (crate 7) (enemy 8) ;; also used for powerups (wall-object 9) ;; also object. door, pusher (blockers?) (projectile 10) (ground-object 11) ;; object, like darkecobarray, platforms (target-attack 12) ;; all target attacks (mother-spider 13) (cak-14 14) ;; unused (blue-eco-suck 15) ;; manipy, orb-cache-top, ) (defenum collide-action :type uint32 :bitfield #t (solid 0) (ca-1 1) ;; sticky? (ca-2 2) ;; target? (ca-3 3) ;; edge grab related (ca-4 4) (ca-5 5) ;; unused? (ca-6 6) ;; swing pole, manipy (ca-7 7) ;; camera (ca-8 8) ;; swingpole (ca-9 9) ;; eco vents? (ca-10 10) (ca-11 11) (ca-12 12) (ca-13 13) (ca-14 14) (ca-15 15) ;; manipy (ca-16 16) ) ;; this field is a bit confusing. you have to have a higher offense to win against an object. ;; so a normal crate has an offense of 1, meaning you have to do _more_ than just touch it to go through it. ;; a scout fly crate has 2, so you have to do _more_ than an normal attack. ;; This system is _only_ for going through objects - there's more logic for deciding if you can break it. (defenum collide-offense :type int8 (no-offense 0) (touch 1) ;; just have to touch (normal-attack 2) ;; any attack (like a normal crate) (strong-attack 3) ;; hit with zoomer, slide, ground pound/flop, flut attack (indestructible 4) ;; can't attack it. ) ;; Every primitive has a prim-core. ;; this is a 32-byte chunk of data that can be pulled out an put in collide caches ;; it stores the transformed world sphere and the collision settings (deftype collide-prim-core (structure) ((world-sphere vector :inline :offset-assert 0) (collide-as collide-kind :offset-assert 16) ;; what are we (enemy, etc) (action collide-action :offset-assert 24) ;; what happens if we collide (physics) (offense collide-offense :offset-assert 28) ;; how hard to we have to hit it? (touch, attack...) (prim-type int8 :offset-assert 29) ;; what type of primtive do we belong to? (extra uint8 2 :offset-assert 30) (quad uint128 2 :offset 0) ) :method-count-assert 9 :size-assert #x20 :flag-assert #x900000020 ) (declare-type collide-shape basic) (declare-type collide-cache-prim structure) ;; the base class for collision shapes. (deftype collide-shape-prim (basic) ((cshape collide-shape :offset-assert 4) ;; our parent collide-shape (prim-id uint32 :offset-assert 8) ;; ? (transform-index int8 :offset-assert 12) ;; ? (prim-core collide-prim-core :inline :offset-assert 16) ;; core data (local-sphere vector :inline :offset-assert 48) ;; sphere, pre transform (collide-with collide-kind :offset-assert 64) ;; things we can collide with ;; overlays of core. (world-sphere vector :inline :offset 16) (collide-as collide-kind :offset 32) (action collide-action :offset 40) (offense collide-offense :offset 44) (prim-type int8 :offset 45) (radius meters :offset 60) ) :method-count-assert 28 :size-assert #x48 :flag-assert #x1c00000048 (:methods (new (symbol type collide-shape uint int) _type_ 0) (dummy-9 (_type_ vector) object 9) ;; ret - symbol | float (dummy-10 (_type_ uint) collide-shape-prim 10) (debug-draw-world-sphere (_type_) symbol 11) (add-fg-prim-using-box (_type_ process-drawable) none 12) (add-fg-prim-using-line-sphere (_type_ process-drawable) none 13) (add-fg-prim-using-y-probe (_type_ process-drawable) none 14) (overlaps-others-test (_type_) symbol 15) (dummy-16 () none 16) (dummy-17 () none 17) (collide-with-collide-cache-prim-mesh (_type_ collide-shape-intersect collide-cache-prim) none 18) (collide-with-collide-cache-prim-sphere (_type_ collide-shape-intersect collide-cache-prim) none 19) (dummy-20 (_type_ collide-kind) symbol 20) (num-mesh (_type_ collide-shape-prim) int 21) (on-platform-test (_type_ _type_ collide-overlap-result float) pat-surface 22) (should-push-away-test () none 23) (dummy-24 () none 24) (dummy-25 (_type_ process-drawable) symbol 25) (set-collide-as! (_type_ collide-kind) none 26) (set-collide-with! (_type_ collide-kind) none 27) ) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Specific Collision Implementation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; generally, these store enough information to tell if you're in collision or not, ;; and if so, what the "pat" is. The meaning of "pat" is unknown, but it's a 32-bit ;; packed data that tells you the material/mode. ;; sphere collision ;; the pat is stored directly here. ;; I believe the "local sphere" is used as the sphere. (deftype collide-shape-prim-sphere (collide-shape-prim) ((pat pat-surface :offset-assert 72) ) :method-count-assert 28 :size-assert #x4c :flag-assert #x1c0000004c (:methods (new (symbol type collide-shape uint) _type_ 0) ) ) ;; mesh collision ;; the pats are stored per tri in the mesh. ;; These meshes interact with a cache automatically (a specific collide-shape-prim-mesh cache, not the ;; more general collide-cache) (deftype collide-shape-prim-mesh (collide-shape-prim) ((mesh collide-mesh :offset-assert 72) (mesh-id int32 :offset-assert 76) (mesh-cache-id uint64 :offset-assert 80) (mesh-cache-tris uint32 :offset-assert 88) ) :method-count-assert 29 :size-assert #x5c :flag-assert #x1d0000005c (:methods (new (symbol type collide-shape uint uint) _type_ 0) (change-mesh (_type_ int) none 28) ) ) ;; A group of collide-shape-prim's (deftype collide-shape-prim-group (collide-shape-prim) ((num-prims int32 :offset-assert 72) (allocated-prims int32 :offset-assert 76) (prim collide-shape-prim 1 :offset-assert 80) (prims collide-shape-prim :dynamic :score 20 :offset 80) ;; added ) :method-count-assert 30 :size-assert #x54 :flag-assert #x1e00000054 (:methods (new (symbol type collide-shape uint int) _type_ 0) (append-prim (_type_ collide-shape-prim) none 28) (dummy-29 (_type_ uint) none 29) ) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Collide Shape ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is sort of the "parent" of all collide prims for a process-drawable. ;; Each process-drawable (pd) should have one collide-shape, which is often the root. ;; It represents: ;; - the location of the thing in hte world ;; - settings abouts collision/navigation ;; - riders (declare-type collide-work structure) (declare-type touching-shapes-entry structure) ;; we're a child of trsqv, so we store a full transform + derivative. (deftype collide-shape (trsqv) ((process process-drawable :offset-assert 140) (max-iteration-count uint8 :offset-assert 144) (nav-flags uint8 :offset-assert 145) (pad-byte uint8 2 :offset-assert 146) (pat-ignore-mask pat-surface :offset-assert 148) (event-self basic :offset-assert 152) (event-other basic :offset-assert 156) (root-prim collide-shape-prim :offset-assert 160) (riders collide-sticky-rider-group :offset-assert 164) (backup-collide-as collide-kind :offset-assert 168) (backup-collide-with collide-kind :offset-assert 176) ) :method-count-assert 56 :size-assert #xb8 :flag-assert #x38000000b8 (:methods (new (symbol type process-drawable collide-list-enum) _type_) (TODO-RENAME-28 (_type_ vector) object 28) ;; ret - symbol | float (CSPG::9) (dummy-29 (_type_ int) none 29) (TODO-RENAME-30 (_type_ vector) object 30) ;; ret - symbol | float (CSPG::9) (debug-draw (_type_) none 31) (dummy-32 (_type_ object collide-kind) none 32) (dummy-33 (_type_ vector collide-kind) none 33) (dummy-34 (_type_ uint) collide-shape-prim 34) (dummy-35 (_type_) symbol 35) (dummy-36 (_type_ bounding-box float collide-kind) symbol 36) (dummy-37 (_type_ vector) none 37) (find-collision-meshes (_type_) symbol 38) (dummy-39 (_type_ collide-shape collide-overlap-result) symbol 39) (dummy-40 (_type_ structure) none 40) ;; ?? - I've seen overlaps-others-params | collide-edge-hold-list (dummy-41 (_type_ attack-info float) vector 41) (dummy-42 (_type_ collide-shape collide-work) none 42) ; collide-work is a guess (dummy-43 (_type_ pull-rider-info) none 43) (dummy-44 (_type_) symbol 44) (dummy-45 (_type_) symbol 45) (set-root-prim! (_type_ collide-shape-prim) collide-shape-prim 46) (dummy-47 (_type_) symbol 47) (clear-collide-with-as (_type_) none 48) (restore-collide-with-as (_type_) none 49) (backup-collide-with-as (_type_) none 50) (set-root-prim-collide-with! (_type_ collide-kind) none 51) (set-root-prim-collide-as! (_type_ collide-kind) none 52) (dummy-53 (_type_ int collide-kind collide-kind) none 53) (dummy-54 (_type_ int collide-offense) none 54) (dummy-55 (_type_ process touching-shapes-entry float float float) none 55) ) ) ;; More complicated collide-shape? (deftype collide-shape-moving (collide-shape) ((rider-time uint64 :offset-assert 184) (rider-last-move vector :inline :offset-assert 192) (trans-old vector 3 :inline :offset-assert 208) (poly-pat pat-surface :offset-assert 256) (cur-pat pat-surface :offset-assert 260) (ground-pat pat-surface :offset-assert 264) (status uint64 :offset-assert 272) (old-status uint64 :offset-assert 280) (prev-status uint64 :offset-assert 288) (reaction-flag uint32 :offset-assert 296) (reaction (function collide-shape-moving collide-shape-intersect vector vector none) :offset-assert 300) (no-reaction (function collide-shape-moving collide-shape-intersect vector vector none) :offset-assert 304) (local-normal vector :inline :offset-assert 320) (surface-normal vector :inline :offset-assert 336) (poly-normal vector :inline :offset-assert 352) (ground-poly-normal vector :inline :offset-assert 368) (ground-touch-point vector :inline :offset-assert 384) (shadow-pos vector :inline :offset-assert 400) (ground-impact-vel meters :offset-assert 416) (surface-angle float :offset-assert 420) (poly-angle float :offset-assert 424) (touch-angle float :offset-assert 428) (coverage float :offset-assert 432) (dynam dynamics :offset-assert 436) (surf surface :offset-assert 440) ) :method-count-assert 65 :size-assert #x1bc :flag-assert #x41000001bc (:methods (set-and-handle-pat! (_type_ pat-surface) none 56) (dummy-57 (_type_ vector) none 57) (dummy-58 (_type_ vector) symbol 58) (dummy-59 (_type_ vector uint float symbol symbol symbol) none 59) (dummy-60 (_type_ float float symbol collide-kind) symbol 60) (TODO-RENAME-61 (_type_ vector vector vector) none 61) (dummy-62 (_type_ vector float) vector 62) (dummy-63 (_type_ vector vector float) float 63) (dummy-64 (_type_ collide-tri-result vector) none 64) ) ) ;;;;;;;;;;;;;;;;;;;; ;; Basic Methods ;;;;;;;;;;;;;;;;;;;; (defmethod new collide-shape-prim ((allocation symbol) (type-to-make type) (cshape collide-shape) (prim-id uint) (size-bytes int)) "Allocate a new collide-shape-prim. It is expected that children of collide-shape-prim override this. NOTE: uses the size-bytes as the TOTAL size of the structure." (let ((obj (object-new allocation type-to-make size-bytes))) (set! (-> obj cshape) (the-as collide-shape cshape)) ;; sphere/mesh? (set! (-> obj prim-id) prim-id) (set! (-> obj prim-core action) (collide-action)) (set! (-> obj prim-core collide-as) (collide-kind)) (set! (-> obj collide-with) (collide-kind)) (set! (-> obj transform-index) -2) (set! (-> obj prim-core offense) (collide-offense no-offense)) (set! (-> obj prim-core prim-type) -2) obj ) ) (defmethod new collide-shape-prim-sphere ((allocation symbol) (type-to-make type) (cshape collide-shape) (prim-id uint)) "Allocate a new sphere primitive" (let ((obj (the collide-shape-prim-sphere ((method-of-type collide-shape-prim new) allocation type-to-make cshape prim-id (size-of collide-shape-prim-sphere))))) (set! (-> obj pat) (new 'static 'pat-surface :mode (pat-mode obstacle))) (set! (-> obj prim-core prim-type) -1) obj ) ) (defmethod new collide-shape-prim-mesh ((allocation symbol) (type-to-make type) (cshape collide-shape) (mesh-id uint) (prim-id uint)) "Allocate a new mesh primitive" (let ((obj (the collide-shape-prim-mesh ((method-of-type collide-shape-prim new) allocation type-to-make cshape prim-id (size-of collide-shape-prim-mesh))))) (set! (-> obj mesh) #f) (set! (-> obj mesh-id) (the int mesh-id)) (set! (-> obj mesh-cache-id) 0) (set! (-> obj prim-core prim-type) 1) obj ) ) (defmethod new collide-shape-prim-group ((allocation symbol) (type-to-make type) (cshape collide-shape) (elt-count uint) (prim-id int)) "Allocate a group of primitives." (let ((obj (the collide-shape-prim-group ((method-of-type collide-shape-prim new) allocation type-to-make cshape (the uint prim-id) (the int (+ (-> type-to-make size) (* (+ elt-count -1) 4))))))) (set! (-> obj allocated-prims) (the int elt-count)) (set! (-> obj num-prims) 0) (set! (-> obj prim-core prim-type) 0) (while (nonzero? elt-count) (+! elt-count -1) (set! (-> obj prim elt-count) (the collide-shape-prim #f)) (nop!) ) obj ) ) (defmethod length collide-shape-prim-group ((obj collide-shape-prim-group)) "How many primitives are used?" (-> obj num-prims) ) (defmethod asize-of collide-shape-prim-group ((obj collide-shape-prim-group)) "How big is this in memory?" (the-as int (+ (-> obj type size) (* (+ (-> obj allocated-prims) -1) 4))) ) (defmethod new collide-shape ((allocation symbol) (type-to-make type) (proc process-drawable) (collide-list-kind collide-list-enum)) "Allocate a new collide-shape and add to a collide-list" (let ((obj (object-new allocation type-to-make (the int (-> type-to-make size))))) (set! (-> obj process) proc) (set! (-> obj max-iteration-count) 1) (set! (-> obj nav-flags) #x1) (set! (-> obj event-self) #f) (set! (-> obj event-other) #f) (set! (-> obj riders) #f) (set! (-> obj root-prim) #f) ;; add a special ignore mask for the camera vs other things. (case (-> proc type symbol) (('camera) (set! (-> obj pat-ignore-mask) (new 'static 'pat-surface :skip #x2 :nocamera #x1)) ) (else (set! (-> obj pat-ignore-mask) (new 'static 'pat-surface :skip #x1 :noentity #x1)) ) ) ;; reset transformation to the origin. (set! (-> obj trans w) 1.0) (quaternion-identity! (-> obj quat)) (vector-identity! (-> obj scale)) ;; add us to right list. (case collide-list-kind (((collide-list-enum hit-by-player)) (add-connection *collide-hit-by-player-list* proc #f obj #f #f)) (((collide-list-enum usually-hit-by-player)) (add-connection *collide-usually-hit-by-player-list* proc #f obj #f #f)) (((collide-list-enum hit-by-others)) (add-connection *collide-hit-by-others-list* proc #f obj #f #f)) (((collide-list-enum player)) (add-connection *collide-player-list* proc #f obj #f #f)) (else (format 0 "Unsupported collide-list-enum in collide-shape constructor!~%")) ) obj ) ) (defmethod new collide-sticky-rider-group ((allocation symbol) (type-to-make type) (riders-amount int)) "Allocate a new collide-sticky-rider-group with space for riders-amount sticky riders." (let ((obj (object-new allocation type-to-make (the int (+ (-> type-to-make size) (the uint (* (1- riders-amount) (size-of collide-sticky-rider)))))))) (set! (-> obj allocated-riders) riders-amount) (set! (-> obj num-riders) 0) obj ) ) (defmethod length collide-sticky-rider-group ((obj collide-sticky-rider-group)) (-> obj num-riders) ) (defmethod asize-of collide-sticky-rider-group ((obj collide-sticky-rider-group)) (the-as int (+ (-> obj type size) (* (+ (-> obj allocated-riders) -1) 32))) ) ;;;;;;;;;;;;;;;;;;;; ;; Fake Meshes ;;;;;;;;;;;;;;;;;;;; ;; These aren't real meshes, but are returned when you collide with the background or water. ;; Background and water collision work differently, but this allows these systems to pretend to be ;; part of the foreground collision system. (define *collide-shape-prim-backgnd* (new 'static 'collide-shape-prim-mesh :cshape #f :prim-core (new 'static 'collide-prim-core :world-sphere (new 'static 'vector :w 204800000.0) :collide-as (collide-kind background) :action (collide-action solid) :offense (collide-offense indestructible) :prim-type 2 ) :local-sphere (new 'static 'vector :w 204800000.0) :mesh #f ) ) (define *collide-shape-prim-water* (new 'static 'collide-shape-prim-mesh :cshape #f :prim-core (new 'static 'collide-prim-core :world-sphere (new 'static 'vector :w 204800000.0) :collide-as (collide-kind water) :action (collide-action solid) :offense (collide-offense indestructible) :prim-type 2 ) :local-sphere (new 'static 'vector :w 204800000.0) :mesh #f ) )