Line data Source code
1 : #ifndef RAGDOLL_H_
2 : #define RAGDOLL_H_
3 :
4 : /* ragdollskel defines a skeletal animation object for use by skelmodel, which
5 : * is able to be dynamically modified by physics (rather than by an animation file)
6 : *
7 : * ragdollskel objects are owned by skelmodel::skeleton objects and therefore there
8 : * is exactly one `ragdollskel` no matter how many entities use a particular model
9 : */
10 :
11 : class ragdollskel final
12 : {
13 : public:
14 5 : ragdollskel() : loaded(false), animjoints(false), eye(-1) {}
15 :
16 : bool loaded, animjoints;
17 :
18 : struct tri final
19 : {
20 : int vert[3];
21 :
22 : /**
23 : * @brief Determines whether two tris share any vertex indices.
24 : *
25 : * Returns true if the the passed triangle has any of the same vertex indices,
26 : * regardless of order (e.g. if this.vert[0] and t.vert[2] are the same, returns true)
27 : *
28 : * @param t the tri to compare to
29 : *
30 : * @return true if any indices from this are the same as any from t
31 : * @return false if no vertex indices match
32 : */
33 : bool shareverts(const tri &t) const;
34 : };
35 : std::vector<tri> tris;
36 :
37 : struct reljoint final
38 : {
39 : int bone, parent;
40 : };
41 : std::vector<reljoint> reljoints;
42 :
43 : struct vert final
44 : {
45 : vec pos;
46 : float radius, weight;
47 : };
48 : std::vector<vert> verts;
49 :
50 : struct joint final
51 : {
52 : int bone, tri, vert[3];
53 : float weight;
54 : matrix4x3 orient;
55 : };
56 : std::vector<joint> joints;
57 :
58 : struct rotlimit final
59 : {
60 : int tri[2];
61 : float maxangle, maxtrace;
62 : matrix3 middle;
63 : };
64 : std::vector<rotlimit> rotlimits;
65 :
66 : struct rotfriction final
67 : {
68 : int tri[2];
69 : };
70 : std::vector<rotfriction> rotfrictions;
71 :
72 : //a distance constraint between two specified vertices
73 : //vert specifies the indices of the vertices in the verts vector, and
74 : //min/maxdist the limits to keep them within
75 : struct distlimit final
76 : {
77 : int vert[2];
78 : float mindist, maxdist;
79 : };
80 : std::vector<distlimit> distlimits;
81 :
82 : int eye;
83 :
84 : void setup();
85 : void addreljoint(int bone, int parent);
86 :
87 : private:
88 : void setupjoints();
89 :
90 : /**
91 : * @brief Adds indices for rotation frictions.
92 : *
93 : * For each pair of triangles in the tris vector of this object where one or more
94 : * vertices in those two triangles refer to the same vertex, adds a new rotfriction
95 : * to the rotfrictions vector with those triangles' indices within the tris vector.
96 : *
97 : * The rotfrictions vector is cleared before adding these entries; does not append
98 : * to existing entries that may be present.
99 : */
100 : void setuprotfrictions();
101 : };
102 :
103 : /*
104 : * ragdolldata defines a class corresponding to a specific instantiation of a ragdoll
105 : * in the context of a dynent. Many ragdolldata objects may point to the same ragdollskel
106 : * object.
107 : */
108 : class ragdolldata final
109 : {
110 : public:
111 : const ragdollskel *skel;
112 : int millis, collidemillis, lastmove;
113 : float radius;
114 : vec offset, center;
115 :
116 : //shadows the elements in skel->tris, should not be resized after construction
117 : std::vector<matrix3> tris;
118 :
119 : //shadows the elements in skel->animjoints
120 : matrix4x3 *animjoints;
121 :
122 : //shadows the elements in skel->reljoints
123 : dualquat *reljoints;
124 :
125 : struct vert final
126 : {
127 : vec oldpos, pos, newpos, undo;
128 : float weight;
129 : bool collided, stuck;
130 5 : vert() : oldpos(0, 0, 0), pos(0, 0, 0), newpos(0, 0, 0), undo(0, 0, 0), weight(0), collided(false), stuck(true) {}
131 : };
132 :
133 : //shadows the elements in skel->verts, should not be resized after construction
134 : std::vector<vert> verts;
135 :
136 : ragdolldata(const ragdollskel *skel, float scale = 1);
137 : ~ragdolldata();
138 :
139 : /**
140 : * @brief Moves the joints of the ragdoll.
141 : *
142 : * Moves the ragdoll joints by an amount indicated by the amount of time
143 : * passed to `ts`. The ragdoll movement will be calculated using
144 : * the ragdollwaterfric variable if water is true, and ragdollairfric if not.
145 : *
146 : * @param water whether the ragdoll is moving through air (false) or water(true)
147 : * @param ts the time to use to calculate physics with, in seconds
148 : */
149 : void move(bool water, float ts);
150 :
151 : /**
152 : * @brief Returns a transformation matrix according to the animation matrix and position
153 : *
154 : * Assumes that there are joints to use to calcuate.
155 : *
156 : * @param i the index of the joint to calculate
157 : * @param anim the animation matrix to transform the joint with
158 : *
159 : * @return an orientation matrix corresponding to the animation data passed
160 : */
161 : matrix4x3 calcanimjoint(int i, const matrix4x3 &anim) const;
162 : void init(const dynent *d);
163 :
164 : private:
165 : int collisions, floating, unsticks;
166 : float timestep, scale;
167 :
168 : std::vector<matrix3> rotfrictions;
169 :
170 : /**
171 : * @brief Sets new values in the tris matrix vector based on ragdollskel tris
172 : *
173 : * Const with respect to all values outside of the vector of tris
174 : *
175 : * Reads values from the associated ragdollskel, and sets the vecs inside the
176 : * corresponding matrix in the ragdolldata as follows:
177 : *
178 : * /|
179 : * /
180 : * m.c/
181 : * /
182 : * v1 / m.a v2
183 : * *---------->*
184 : * |
185 : * |
186 : * |
187 : * m.b|
188 : * v
189 : *
190 : *
191 : * *
192 : * v3
193 : *
194 : * ----→ ----→
195 : * m.c = v1 v2 x v1 v3
196 : * --→ ----→
197 : * m.b = m.c x v1 v2
198 : *
199 : * m.a points from v1 to v2
200 : * m.b points from v1 to v3
201 : * m.c points along the normal of the triangle v1, v2, v3
202 : *
203 : * Prior values that may be in the matrix vector are disregarded and have no
204 : * effect on the output values.
205 : */
206 : void calctris();
207 :
208 : /**
209 : * @brief Calculates the ragdolldata's radius and center position
210 : *
211 : * Sets the center position to be the average of all the vertices in the ragdoll
212 : * Sets the radius to be the distance between the center and the farthest vert
213 : *
214 : * This is not necessarily the smallest sphere encapsulating all of the points
215 : * in the vertex array, since that would be the midpoint of the farthest points in
216 : * the vertex array.
217 : */
218 : void calcboundsphere();
219 : void constrain(vec &cwall);
220 :
221 : /**
222 : * @brief Adds weights to keep pairs of vertices within specified bounds
223 : *
224 : * For each vertex pair in the defined distlimits vector, adds weights to
225 : * those verts to pull or push those vertices to lie within the specified min/maxdist
226 : * distance apart.
227 : *
228 : * Modifies vertex weights and newpos fields and no other components of ragdolldata.
229 : */
230 : void constraindist();
231 :
232 : /**
233 : * @brief Applies a rotation around a specified axis to a pair of triangles.
234 : *
235 : * Modifies the vertices pointed to by the two assigned tri objects by rotating them
236 : * to the amount indicated by the angle and about the axis specified by axis.
237 : *
238 : * For each vertex indicated by the indices in the triangle objects, adds to the
239 : * newpos vec a value corresponding to the rotation desired. Increments the weight
240 : * field for each vertex so modified by one. Does not modify the vert's pos or oldpos,
241 : * only newpos.
242 : *
243 : * @param t1 the first triangle to retrieve vertices with
244 : * @param t2 the second triangle to retrieve vertices with
245 : * @param angle the angle in radians to rotate by
246 : * @param axis the axis by which to rotate around
247 : */
248 : void applyrotlimit(const ragdollskel::tri &t1, const ragdollskel::tri &t2, float angle, const vec &axis);
249 :
250 : /**
251 : * @brief Calculates and applies a rotation limit each defined rotation limit
252 : *
253 : * For each rotlimit in the associated skeleton, calculates the angle and rotation
254 : * from that rotlimit and applies it to the associated vertices.
255 : */
256 : void constrainrot();
257 :
258 : /**
259 : * @brief Sets the shadowing elements in rotfrictions according to their respective values in the pointed ragdollskel.
260 : *
261 : * For each member of ragdolldata::rotfrictions, sets its value to the transposed multiplication of
262 : * the data pointed to by the indices of the first two vertices in the ragdollskel::rotfrictions tri data.
263 : *
264 : * Previous values in ragdolldata::rotfrictions are ignored and overwritten.
265 : */
266 : void calcrotfriction();
267 :
268 : /**
269 : * @brief Applies rotation friction and propagates it to the model's vertices
270 : *
271 : * Calculates rotation limits with applyrotlimit() and then moves the set `newpos`
272 : * values to the `pos` values in each vert.
273 : *
274 : * @param ts the time duration to apply in seconds
275 : */
276 : void applyrotfriction(float ts);
277 :
278 : /**
279 : * @brief Modifies stuck verticies in the vertex array.
280 : *
281 : * Only affects those vertices which have the `stuck` field set to `true`.
282 : *
283 : * Moves those `stuck` vertices towards the average position of the unstuck vertices,
284 : * with a magnitude equal to the `speed` parameter.
285 : *
286 : * @param speed the magnitude by which to modify stuck vertices
287 : *
288 : */
289 : void tryunstick(float speed, vec &cwall);
290 :
291 : /**
292 : * @brief Checks collision of `dir` with spherical volume at `pos` with radius `radius`.
293 : *
294 : * Checks collision of defined sphere with the cubeworld, in direction `dir`.
295 : * physics' `collide()` used for collision detection against the cubeworld.
296 : *
297 : * @param pos positon of sphere center
298 : * @param dir direction to check collision against
299 : * @param radius radius of sphere center
300 : * @param [out] cwall collision wall data found by the collision check
301 : *
302 : * @return true if collision occured
303 : * @return false if no collision occured
304 : */
305 : static bool collidevert(const vec &pos, const vec &dir, float radius, vec &cwall);
306 : };
307 :
308 : /**
309 : * @brief Deletes the heap-allocated ragdoll associated with the passed dynent.
310 : *
311 : * If there is no ragdoll associated with `d`, then there is no effect.
312 : *
313 : * @param d the dynent to delete the ragdoll of
314 : */
315 : extern void cleanragdoll(dynent *d);
316 :
317 : #endif
|