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