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