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