-
-
Notifications
You must be signed in to change notification settings - Fork 32
/
region.lisp
128 lines (108 loc) · 4.96 KB
/
region.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
(in-package #:org.shirakumo.fraf.kandria)
(defclass region (bag ephemeral)
((chunk-graph :initform NIL :accessor chunk-graph)
(bvh :initform (bvh:make-bvh) :reader bvh)
(depot :initarg :depot :accessor depot)
(indefinite-extent-entities :initform () :accessor indefinite-extent-entities)))
(defgeneric load-region (depot region))
(defgeneric save-region (region depot &key version &allow-other-keys))
(defmethod save-region ((scene scene) target &rest args)
(apply #'save-region (node 'region scene) target args))
(defmethod save-region :around (region target &rest args &key (version T))
(apply #'call-next-method region target :version (ensure-version version) args))
(defmethod save-region (region (pathname pathname) &key version (if-exists :supersede))
(let ((depot (depot:realize-entry (depot:from-pathname pathname) T)))
(save-region region depot :version version)
(depot:commit depot)))
(defmethod save-region ((region region) (depot depot:depot) &key version)
(v:info :kandria.region "Saving ~a to ~a" region depot)
(depot:with-open (tx (depot:ensure-entry "meta.lisp" depot) :output 'character)
(let ((stream (depot:to-stream tx)))
(princ* (list :identifier 'region :version (type-of version)) stream)
(princ* (encode-payload region NIL depot version) stream))))
(defmethod load-region ((pathname pathname) scene)
(depot:with-depot (depot pathname)
(load-region depot scene)))
(defmethod load-region (thing (scene scene))
(let ((new (load-region thing NIL)))
(when (node 'region scene)
(leave (node 'region scene) scene))
(enter new scene)
new))
(defmethod chunk-graph ((region region))
(or (slot-value region 'chunk-graph)
(setf (chunk-graph region) (make-chunk-graph region))))
(defmethod load-region ((depot depot:depot) (null null))
(v:info :kandria.region "Loading ~a" depot)
(destructuring-bind (header info) (parse-sexps (depot:read-from (depot:entry "meta.lisp" depot) 'character))
(decode-payload
info (type-prototype 'region) depot
(destructuring-bind (&key identifier version) header
(assert (eql 'region identifier))
(coerce-version version)))))
(defmethod clear :after ((region region))
(clear (bvh region)))
(defmethod enter :after ((object renderable) (region region))
(unless (typep object 'sized-entity)
(push object (indefinite-extent-entities region)))
(when (container region)
(loop for pass across (passes (container region))
do (when (object-renderable-p object pass)
(enter object pass)))))
(defmethod leave :after ((object renderable) (region region))
(unless (typep object 'sized-entity)
(setf (indefinite-extent-entities region) (delete object (indefinite-extent-entities region))))
(when (container region)
(loop for pass across (passes (container region))
do (when (object-renderable-p object pass)
(leave object pass)))))
(defmethod enter :after ((unit sized-entity) (region region))
(bvh:bvh-insert (bvh region) unit))
(defmethod leave :after ((unit sized-entity) (region region))
(bvh:bvh-remove (bvh region) unit))
(defmethod scan ((region region) target on-hit)
(do-fitting (object (bvh region) target)
(unless (eq object target)
(let ((hit (scan object target on-hit)))
(when hit
(return hit))))))
(defmethod scan ((region region) (target game-entity) on-hit)
(let ((loc (location target))
(bsize (bsize target)))
(with-tvec (vec (- (vx2 loc) (vx2 bsize) 20)
(- (vy2 loc) (vy2 bsize) 20)
(+ (vx2 loc) (vx2 bsize) 20)
(+ (vy2 loc) (vy2 bsize) 20))
(do-fitting (object (bvh region) vec)
(unless (eq object target)
(let ((hit (scan object target on-hit)))
(when hit (return hit))))))))
(defmethod scan ((region region) (target vec4) on-hit)
(with-tvec (vec (- (vx4 target) (vz4 target))
(- (vy4 target) (vw4 target))
(+ (vx4 target) (vz4 target))
(+ (vy4 target) (vw4 target)))
(do-fitting (object (bvh region) vec)
(let ((hit (scan object target on-hit)))
(when hit (return hit))))))
(defmethod unit (name (region region))
(sequences:dosequence (entity region)
(when (and (typep entity 'entity)
(eql name (name entity)))
(return entity))))
(defmethod bsize ((region region))
(let ((x- most-positive-fixnum)
(x+ most-negative-fixnum)
(y- most-positive-fixnum)
(y+ most-negative-fixnum))
(flet ((expand (loc bs)
(setf x- (min x- (- (vx loc) (vx bs))))
(setf x+ (max x+ (+ (vx loc) (vx bs))))
(setf y- (min y- (- (vy loc) (vy bs))))
(setf y+ (max y+ (+ (vy loc) (vy bs))))))
(for:for ((entity over region))
(when (typep entity 'sized-entity)
(expand (location entity) (bsize entity)))))
(values (vec (/ (- x+ x-) 2)
(/ (- y+ y-) 2))
(vec x- y- x+ y+))))